淺談操作系統-進程與線程
一、進程
1.進程的描述
進程可以理解為程序的一次執行,也可以理解為程序運行的一個實例。 進程是分配資源的基本單位
一個進程由三部分組成:進程式控制制塊PCB(Process Control Block),有關程序段,該程序段對其操作的數據結構集。進程到底是什麼樣子呢?不妨讓我們打開任務管理器。
這樣我們不僅僅看到了每個正在運行的進程的名稱,在詳細信息里還能看到了進程分配的內存空間,pid等屬性。
2. 進程式控制制塊PCB
進程的PCB是系統感知進程的唯一實體。
所以說到底,對進程進行操作,也可以理解為對PCB進行操作。 PCB是要常駐內存的。
所以在創建進程的時候,就是分配一個PCB,裡面記錄了進程的各種信息,這些信息都包括:- 描述信息:進程的標識號、用戶標識號、家族關係
- 控制信息:進程當前狀態、進程優先順序、程序開始地址、計時信息、通信信息
- 資源管理信息:管理內存數據結構的指針、文件系統的指針等包括存儲器的信息,IO設備、文件系統的信息。
- CPU現場保護結構:各個寄存器的內容
2.1 PCB的組織方式
一般來說,系統把所有PCB組織在一起,並把他們放在內存的固定區域,構成PCB表。
PCB表的大小決定了系統中最多可同時存在的進程的個數。 ① 鏈接方式:把具有同一狀態的PCB,鏈接成一個隊列,這樣可以形成若干就緒隊列、阻塞隊列和空白隊列等,優先順序高的進程的PCB排在前面。② 索引方式:系統根據所有進程的狀態建立幾張索引表,如就緒索引表,阻塞索引表等,並把各索引表在內存的首地址記錄在內存的一些專用單元中,在每個索引表的表目中,記錄具有相應狀態的某個PCB在PCB表中的地址。
2.2 EOS中的PCB
以EOS操作系統為例,看一下EOS是如何定義PCB的數據結構
typedef struct _PROCESS { BOOLEAN System; // 是否系統進程 UCHAR Priority; // 進程的優先順序 PMMPAS Pas; // 進程地址空間 PHANDLE_TABLE ObjectTable; // 進程的內核對象句柄表 LIST_ENTRY ThreadListHead; // 線程鏈表頭 PTHREAD PrimaryThread; // 主線程指針 LIST_ENTRY WaitListHead; // 等待隊列,所有等待進程結束的線程都在此隊列等待。 PSTR ImageName; // 二進位映像文件名稱 PSTR CmdLine; // 命令行參數 PVOID ImageBase; // 可執行映像的載入基址 PPROCESS_START_ROUTINE ImageEntry; // 可執行映像的入口地址 HANDLE StdInput; HANDLE StdOutput; HANDLE StdError; ULONG ExitCode; // 進程退出碼} PROCESS;
3. 進程的狀態
一個進程至少具有5種基本狀態:初始態、執行狀態、等待(阻塞)狀態、就緒狀態、終止狀態 初始狀態:進程剛被創建,由於其他進程正佔有CPU所以得不到執行,只能處於初始狀態。 執行狀態:任意時刻處於執行狀態的進程只能有一個。 就緒狀態:只有處於就緒狀態的經過調度才能到執行狀態 等待狀態:進程等待某件事件完成 停止狀態:進程結束
有的系統,為了暫時緩和內存的緊張狀態,或為了調節系統負荷,又引入了掛起的功能:暫時掛起一部分進程,把他們從內存臨時換出到外存。 阻塞掛起:進程在外存並等待某事件的出現 就緒掛起:進程在外存,但只要進入內存,就可以運行
4. 進程式控制制
創建、撤銷進程以及完成進程各狀態之間的轉換,由具有特定功能的原語完成
- 進程創建原語
- 進程撤銷原語
- 阻塞原語
- 喚醒原語
- 掛起原語
- 激活原語
- 改變進程優先順序
進程創建
一個進程可以創建一個子進程,子進程會繼承父進程所擁有的資源,如繼承父進程打開的文件,分配到的緩衝區等。
當子進程被撤銷時,應該講其從父進程哪裡獲得的資源歸還給父進程,此外,撤銷父進程時,也必須同時撤銷其所有的子進程。引起進程創建的事件如下:
- 用戶登錄
- 作業調度
- 提供服務
- 應用請求
進程創建的步驟:
- 創建PCB
- 賦予一個唯一的進程標識符pid
- 為新進程分配資源,為新進程的程序和數據以及用戶棧分配必要的內存空間
- 初始化PCB(初始化標識信息,將系統分配的標識符和父進程標識符填入新的PCB中;初始化處理機狀態信息,使程序計數器指向程序的入口地址,使棧指針指向棧頂;初始化處理機控制信息,將進程的狀態設置為就緒狀態或靜止就緒狀態。)
- 將新進程插入到就緒隊列
進程撤銷
引起進程的撤銷的事件如下:
- 正常結束:進程運行完畢
- 異常結束:進程運行中由於出現錯誤而終止。如越界等
- 外界干預:進程應外界的請求而終止運行,如操作員或操作系統干預,父進程請求
進程撤銷的步驟:
- 根據被終止的進程的標識符,從PCB集合匯總檢索除該進程的PCB,從中讀出該進程的狀態。
- 若被終止的進程正處於執行狀態,應立即終止該進程的執行,並置調度標誌位真,用於指示該進程被終止後應重新進行調度。
- 若該進程還有子孫進程,還應將其子孫進程予以終止,以防他們成為不可控的進程。
- 將被終止的進程所擁有的全部資源,或者歸還給其父進程,或者歸還給操作系統。
- 將被終止的進程PCB從所在隊列或鏈表中移出,等待其他程序來搜集信息。
進程阻塞
引起進程阻塞的事件:
- 請求系統服務:當正在執行的進程請求操作系統提供服務時,由於某種原因,操作系統並不立即滿足該進程的要求,該進程只能轉變為阻塞狀態來等待。
- 啟動某種操作:當進程啟動某種操作後,如果該進程必須在該操作完成之後才能繼續執行,則必須先使該進程阻塞,以等待該操作完成。
- 新數據尚未到達:對於相互合作的進程,如果其中一個進程需要先獲得另一合作進程提供的數據後才能對數據進行處理,則只要其所需數據尚未到達,該進程只有(等待)阻塞。
- 無新工作可做:系統往往設置一些具有某些特定功能的系統進程,每當這種進程完成任務後,便把自己阻塞起來以等待新任務到來。
進程阻塞的步驟:
- 保護CPU現場到PCB
- PCB插入到阻塞隊列
進程喚醒
- PCB插入到就緒隊列
要注意,進程阻塞和喚醒的原語不能出現在一個進程內
二、線程
1. 線程的描述
引入線程是因為創建進程、進程間切換的開銷比較大
同一個進程下的多個線程貢獻這個進程的資源 線程是進程的一條執行路徑,共享進程的地址空間 線程也是CPU調度的一個基本單位2. 線程式控制制塊TCB
EOS中TCB的數據結構如下
//// 線程對象結構體 (TCB)。//typedef struct _THREAD { PPROCESS Process; // 線程所屬進程指針 LIST_ENTRY ThreadListEntry; // 進程的線程鏈表項 UCHAR Priority; // 線程優先順序 UCHAR State; // 線程當前狀態 ULONG RemainderTicks; // 剩餘時間片,用於時間片輪轉調度 STATUS WaitStatus; // 阻塞等待的結果狀態 KTIMER WaitTimer; // 用於有限等待喚醒的計時器 LIST_ENTRY StateListEntry; // 所在狀態隊列的鏈表項 LIST_ENTRY WaitListHead; // 等待隊列,所有等待線程結束的線程都在此隊列等待。 // // 為了結構簡單,EOS沒有對內核進行隔離保護,所有線程都運行在內核狀態,所以目 // 前線程沒有用戶空間的棧。 // PVOID KernelStack; // 線程位於內核空間的棧 CONTEXT KernelContext; // 線程執行在內核狀態的上下文環境狀態 // // 線程必須在所屬進程的地址空間中執行用戶代碼,但可在任何進程的地址空間中執行 // 內核代碼,因為內核代碼位於所有進程地址空間共享的系統地址空間中。 // PMMPAS AttachedPas; // 線程在執行內核代碼時綁定進程地址空間。 PTHREAD_START_ROUTINE StartAddr; // 線程的入口函數地址 PVOID Parameter; // 傳遞給入口函數的參數 ULONG LastError; // 線程最近一次的錯誤碼 ULONG ExitCode; // 線程的退出碼} THREAD;
推薦閱讀: