1. 引言

我們知道,每個進程在內核中都有一個進程控制塊(PCB)來維護進程相關的信息,Linux內核的進程控制塊是task_struct結構體。現在我們全面瞭解一下其中都有哪些信息。

目前讀者並不需要理解這些信息的細節,在隨後幾章中講到某一項時會再次提醒讀者它是保存在PCB中的。

forkexec是本章要介紹的兩個重要的系統調用。fork的作用是根據一個現有的進程複製出一個新進程,原來的進程稱為父進程(Parent Process),新進程稱為子進程(Child Process)。系統中同時運行着很多進程,這些進程都是從最初只有一個進程開始一個一個複製出來的。在Shell下輸入命令可以運行一個程序,是因為Shell進程在讀取用戶輸入的命令之後會調用fork複製出一個新的Shell進程,然後新的Shell進程調用exec執行新的程序。

我們知道一個程序可以多次加載到內存,成為同時運行的多個進程,例如可以同時開多個終端窗口運行/bin/bash,另一方面,一個進程在調用exec前後也可以分別執行兩個不同的程序,例如在Shell提示符下輸入命令ls,首先fork創建子進程,這時子進程仍在執行/bin/bash程序,然後子進程調用exec執行新的程序/bin/ls,如下圖所示。

圖 30.1. fork/exec

fork/exec

第 3 節 “open/close”中我們做過一個實驗:用umask命令設置Shell進程的umask掩碼,然後運行程序a.out,結果a.out進程的umask掩碼也和Shell進程一樣。現在可以解釋了,因為a.out進程是Shell進程的子進程,子進程的PCB是根據父進程複製而來的,所以其中的umask掩碼也和父進程一樣。同樣道理,子進程的當前工作目錄也和父進程一樣,所以我們可以用cd命令改變Shell進程的當前目錄,然後用ls命令列出那個目錄下的檔案,ls進程其實是在列自己的當前目錄,而不是Shell進程的當前目錄,只不過ls進程的當前目錄正好和Shell進程相同。有一個例外,子進程PCB中的進程id和父進程是不同的。