原文鏈接:http://www.orlion.ga/1015/ 一、進程 每個進程在內核中都有一個進程式控制制塊(PCB)來維護進程相關的信息,linux內核的進程式控制制塊是task_struct結構體,其中有: 進程id。系統中每個進程有一個唯一的id,在C語言中用pid_t類型表示,是一個非負正是 進 ...
原文鏈接:http://www.orlion.ga/1015/
一、進程
每個進程在內核中都有一個進程式控制制塊(PCB)來維護進程相關的信息,linux內核的進程式控制制塊是task_struct結構體,其中有:
-
進程id。系統中每個進程有一個唯一的id,在C語言中用pid_t類型表示,是一個非負正是
-
進程的狀態,有運行、掛起、停止、僵屍等狀態
-
進程切換時需要保存和恢復的一些CPU寄存器
-
描述虛擬地址空間的信息
-
描述控制終端的信息
-
當前工作目錄
-
umask掩碼
-
文件描述符表,包含很多指向file結構體的指針
-
和信號相關的信息
-
用戶id和組
-
控制終端、Session和進程組。
-
進程可以使用的資源上限
fork的作用是根據一個現有的進程(父進程)複製出一個新進程(子進程),系統中同時運行著多個進程,這些進程都是從最初只有一個進程開始一個一個複製出來的,在Shell下輸入命令可以運行一個程式,是因為Shell進程在讀取用戶輸入的命令之後會調用fork複製出一個新的Shell進程,然後新Shell進程調用exec執行新的程式。
一個程式可以多次載入到記憶體中成為同時運行的多個進程,例如可以同時開多個終端運行/bin/bash。一個進程在調用exec前後也可以分別執行兩個不同的程式,例如在Shell下輸入命令ls,首先fork創建子進程,這時子進程仍在執行/bin/bash程式然後子進程調用exec執行新的程式/bin/ls。如下圖所示:
子進程的PCB是根據父進程複製而來的,所以其中的umask掩碼也和父進程一樣。同樣道理子進程的當前工作目錄也和父進程一樣,所以我們用cd改變Shell進程的工作目錄,然後ls列出那個目錄下的文件,ls進程其實是在列自己的當前目錄,而不是Shell進程的當前目錄,只不過ls進程的目錄和Shell的目錄一樣。但是子進程PCB中的進程id和父進程不同。
二、環境變數
exec系統調用執行新程式時會把命令行參數和環境變數表傳遞給main函數,它們在整個進程地址空間中的位置如下所示:
和命令行參數argv類似,環境變數表也是一組字元串,如下圖所示:
libc定義的全局變數environ指向環境變數表,environ沒有包含在頭文件中,所以在使用時要用extern聲明。例:
#include <stdio.h> int main(void) { extern char **environ; int i; for (i=0; environ[i] != NULL; i++) printf("%s\n", environ[i]); return 0; }
執行結果為:
由於父進程在調用fork創建子進程時會把自己的環境變數表也複製給子進程,所以列印的環境變數和Shell進程列印的環境變數是相同的。環境變數定義了進程的運行環境。
可以用char *getenv(const char *name)獲取name在環境變數表中對應的value。
可以用int setenv(const char *name, const char *value, int rewrite);設置環境變數。
可以用void unsetenv(const char *name);刪除name的定義。
在子進程中修改環境變數並不會改變父進程的環境變數。