主要内容
①程序建立
②執行程式
③程序終止
④程序屬性
1:程序辨別符
1.1
①每個程序都有一份非負整數表示的唯一程序ID
②程序ID可以重新,一個程序結束之後可以,這個ID可以被其他程序所使用,當UNIX普遍都采用了延遲重用算法。使得某一個程序結束之後其ID不會馬上被新的程序所使用,以防止将新程序誤認為之前結束的程序.
③程序ID為0的通常是排程程序,常稱為交換程序(swapper),屬于核心的一部分,不執行磁盤上的任何程式,因而也稱為系統程序。
④程序ID為1的通常是init程序,負責自舉核心之後,啟動一個UNIX系統。注意它是一個普通使用者程序,但是以超級使用者的權限運作。
⑤ID為2的是頁守護程序,負責支援虛拟存儲系統的分頁操作
1.2擷取程序辨別的函數
#include<unistd.h>
pid_t getpid(); //擷取程序ID
pid_t getppid(); //擷取父程序ID
pid_t getuid(); //擷取實際使用者ID,運作這個程序的使用者是誰
pid_t geteuid(); //擷取有效使用者ID,用于檔案通路權限檢查,決定了對于某個檔案的通路權限
pid_t getgid();
pid_t getegid();
2:fork函數
2.1
①函數原型
#include<unistd.h>
pid_t fork(void);
②建立一個新的程序
③調用一次,傳回兩次子程序中傳回0,父程序當中傳回子程序的ID
④子程序是父程序的副本,獲得了父程序的程序空間資料,包括資料段,bss段,堆,棧。而正文段則是父子程序共享。現在很多系統的實作并不采用完全複制的方法,而是采用寫時複制技術。父子程序共享,核心将此區域設定為隻讀,父子程序任何一個試圖修改,核心都将為修改區域的記憶體制作一個副本。
2.2檔案共享
①父子程序共享檔案表項
②通常對父子程序對檔案描述符的處理方法
a:父程序等待子程序操作檔案
b:父子程序使用不同的代碼段,即在fork之後,父子程序各自關閉不需要的檔案描述符。
③父子程序檔案共享圖示
3.3fork的兩種常見用法
①父程序希望複制自己,父子程序執行不同代碼.例如網絡伺服器,父程序等待請求,當請求到來之後,子程序處理請求,而父程序繼續等待下次請求。
②一個程序需要執行一個不同的程式, 子程序fork傳回之後立刻調用exec
3:vfork函數
3.1 vfork和fork的差別
①vfork的目的就是執行一個新的程式.
②vfork并不複制父程序的位址空間,相反它在調用exit或者exec之前它在父程序的位址空間中運作.
③vfork保證子程序先執行,隻有當子程序調用exec或者exit之後,父程序才有可能被排程運作。
4:程序的結束
4.1
無論是正常退出還是異常終止的程序,其父程序都可以獲得其終止狀态.正常退出的程序,通過調用exit _exit 或者_Exit将其退出狀态作為參數傳遞給函數而對于異常終止的程序,核心産生一個訓示異常終止原因的終止狀态
4.2
父程序已經結束的程序都将會被init程序收養
4.3僵死程序
一個 已經終止,但父程序沒有對其進行善後處理的程序稱為僵死程序.
一個程序結束時,如果父程序仍然存在,而且父程序在fork之前既沒有安裝SIGCHID信号處理函數調用wait/waitpid等待子程序結束,也沒有顯示的忽略該信号,則這個子程序在父程序結束之前都為僵死程序,它已經放棄了幾乎所有記憶體空間,沒有任何可執行代碼,也不能被排程,僅僅在程序清單中保留一個位 置,記載該程序的退出狀态等資訊供其他程序收集,除此之外,僵屍程序不再占有任何記憶體空間.
5:wait和waitpid
5.1函數原型
#include<sys/wait.h>
pid_t wait(int *statloc)
pid_t wait(pid_t pid, int *statloc, int options)
5.2
一個程序正常或者異常終止,核心都會向其父程序發送一個SIGCHLD信号,由于子程序的終止可能發生在任何時候,是以這也是個異步信号。對于這個信号父程序可以選擇忽略,或者提供一個信号處理函數。如果什麼不做,系統是預設忽略,如果采用預設忽略的方式那麼子程序就會成為一個僵死程序(父程序為init除外)
。如果父程序調用了wait或者waitpid則會發送如下情況。
a:如果所有子程序均在運作,則阻塞
b:如果一個子程序已經終止,正等待父程序擷取其終止狀态,則取得該子程序的終止狀态立即傳回。
c:如果沒有任何子程序則立即傳回錯誤
example:
#include<stdio.h>
#include<sys/wait.h>
int main()
{
int stats;
pid_t pid;
if( (pid = fork()) < 0){
printf("fork error\n");
return 1;
}
else if(pid == 0){
int i;
printf("this is the child process\n");
for(i=0; i<10; ++i){
sleep(1);
printf("ok!\n");
}
}
else{
if(wait(&stats) != pid){
printf("wait error\n");
}
printf("stats:%d\n",stats);
return 0;
}
}運作結果如下
5.3 wait和waitpid的差別
wait在第一個子程序終止之前會使父程序一直處于阻塞狀态而waitpid不會,waitpid有若幹個選項可以控制所等待的程序。
注意調用一次之會等待第一個程序的結束,
5.4
wait.h中定義了四個互斥的宏來擷取終止原因。p180
5.5fork兩次,一種避免産生僵死程序的方法
原理:程序A fork出程序B,之後程序B發 fork出程序C,程序B立即退出,程序C調用sleep函數保證程序B先退出,程序A中調用waitpid函數等待程序B退出。
我們實際需要的新的程序是C,程序B做個中間程序,因為程序B結束之後,程序C成為init的子程序,是以它不會成為僵死程序,而程序A在程序B結束之後它就不會再阻塞。
6:exec函數
6.1:總共有六個exec函數,差別如下
p:使用環境變量中的PATH
l:使用list
v:使用數組
e:使用自定義的環境變量
6.2:大部分unix實作當中隻有一個execve是系統調用,其他六個均為庫函數