我們知道,每個進程在內核中都有一個進程控制塊(PCB)來維護進程相關的信息,Linux內核的進程控制塊是task_struct
結構體。現在我們全面瞭解一下其中都有哪些信息。
目前讀者並不需要理解這些信息的細節,在隨後幾章中講到某一項時會再次提醒讀者它是保存在PCB中的。
fork
和exec
是本章要介紹的兩個重要的系統調用。fork
的作用是根據一個現有的進程複製出一個新進程,原來的進程稱為父進程(Parent Process),新進程稱為子進程(Child Process)。系統中同時運行着很多進程,這些進程都是從最初只有一個進程開始一個一個複製出來的。在Shell下輸入命令可以運行一個程序,是因為Shell進程在讀取用戶輸入的命令之後會調用fork
複製出一個新的Shell進程,然後新的Shell進程調用exec
執行新的程序。
我們知道一個程序可以多次加載到內存,成為同時運行的多個進程,例如可以同時開多個終端窗口運行/bin/bash
,另一方面,一個進程在調用exec
前後也可以分別執行兩個不同的程序,例如在Shell提示符下輸入命令ls
,首先fork
創建子進程,這時子進程仍在執行/bin/bash
程序,然後子進程調用exec
執行新的程序/bin/ls
,如下圖所示。
在第 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和父進程是不同的。