五、深入理解進程概念
5.1 進程的分類
1、系統進程/用戶進程
這里系統進程的優先級要高2、前臺進程/后臺進程
用戶一般只和前臺進程交互。3、
CPU
密集型進程/IO
密集型進程
5.2 進程層次結構
-
UNIX
中是一個進程家族樹的概念:init
為根進程。于是如果某一個進程結束了,那么其子孫進程都必須結束。 -
Windows
中的所有進程的地位都是相同的。
5.3 進程和程序的區別
- 進程更能準確刻畫并發,而程序不能
- 程序是靜態的,進程是動態的
- 進程有生命周期的,有誕生有消亡,是短暫的;而程序是相對長久的
- 一個程序可對應多個進程
- 進程具有創建其他進程的功能
5.4 進程的地址空間
操作系統為每個進程分配了一個地址空間。這里我們看一個例子:
1
這個程序我們從命令行中輸入數據,比如:
myval 7
myval 8
此時我們會發現雖然進程不同,但是打印出來的地址確實一樣的。這里我們從進程地址空間來分析:
2
說明:上面的兩個進程都有這樣一個地址空間,也就是說這兩個進程是在不同的地址空間上的相同的位置,所以雖然地址是一樣的,但是實際上在實際內存中的地址是不一樣的。
5.5 進程映像
對進程執行活動全過程的靜態描述(快照)。由進程地址空間內容、硬件寄存器內容及與該進程相關的內核數據結構、內核棧組成
- 與用戶相關:進程地址空間(代碼段、數據段、堆和棧、共享棧等)
- 與寄存器相關:程序計數器、指令寄存器、程序狀態寄存器、棧指針、通用寄存器等的值
- 與內核相關:
- 靜態部分:
PCB
及各種資源數據結構 - 動態部分:內核棧(不同進程在進入內核后使用不同的內核棧)
- 靜態部分:
5.6 上下文切換
- 將
CPU
硬件狀態從一個進程換到另一個進程的過程稱為上下文切換,其實就是運行環境的切換。 - 進程運行時,其硬件狀態保存在
CPU
上的寄存器中。寄存器有:程序計數器、程序狀態寄存器、棧指針、通用寄存器、其他控制寄存器的值 - 進程不運行時,這些寄存器的值保存在進程控制塊中;當操作系統要運行一個新的進程時,將進程控制塊中相關值送到對應的寄存器中。
六、線程
6.1 線程的引入
引入線程有三個理由:
- 應用的需要
- 開銷的考慮
- 性能的考慮
6.1.1 應用的需要
我們看一個例子,一個web
服務器的工作方式:
- 從客戶端接收網頁請求
- 從磁盤上檢索相關的網頁,讀入內存(此時進程是停止的,直到讀取完畢)
- 將網頁返回給對應的客戶端
可以看到每次從磁盤讀取的時候進程都是暫停的,這樣會導致性能低下。那如何提高服務器的工作效率?通常情況下是使用網頁緩存的方式解決。如果沒有線程的情況下的兩種解決方案:
一個服務進程
這種情況下也是一種順序編程,雖然采用了緩存機制,但是性能同樣不高。而如果設置多個進程,這多個進程之間又是相互獨立的,有獨立的地址空間,所以不能共享信息。有限狀態機
這種方式編程模型復雜,采用非阻塞的I/O
。
多線程的解決方式
1
說明:這是一個多線程的
web
服務器的工作方式,首先讀取客戶端的請求,之后由分派線程將各個任務分派給工作線程,同樣這里還是采用了網頁緩存。于是我們可以看到一個web
服務器的實現有三種方式:2
6.1.2 開銷的考慮
3
6.1.3 性能的考慮
如果有多個處理器的話,一個進程就會有多個線程同時在執行了,這樣可以極大的提高運行 性能。
6.2 線程的基本概念
4
線程的屬性
- 有標識符
ID
- 有狀態及狀態轉換
-->
需要提供一些操作 - 不運行時需要保存的上下文(程序計數器等寄存器)
- 有自己的棧和棧指針
- 共享所在進程的地址空間和其他資源
- 創建、撤銷另一個線程(程序開始是以一個單線程方式運行的)
6.3 線程機制的實現
一般有三種實現機制:
- 用戶級線程
- 核心級線程
- 混合(兩者結合)方法
6.3.1 用戶級線程
5
說明:可以看到線程是有運行時系統管理的,在內核中只有進程表。典型例子就是
UNIX:
POSIX線程庫--PTHREAD
6
小結:
有點:
- 線程切換快
- 調度算法是應用程序特定的
- 用戶級線程可運行在任何操作系統上(只需要實現線程庫)
缺點:
- 內核只將處理器分配給進程,同一進程中的兩個線程不能同時運行于兩個處理器上
- 大多數系統調用是阻塞的,因此,由于內核阻塞進程,故進程中所有線程也被阻塞。(可以在調用之前判斷進行解決,如果是阻塞線程,那么就換其他線程)
6.3.2 核心級線程
7
6.3.3 混合模型
- 線程創建在用戶空間完成
- 線程調度等在核心態完成
- 例子如
Solaris
操作系統