天天看點

unix/linux多程序程式設計2-程序控制

主要内容

①程序建立

②執行程式

③程序終止

④程序屬性

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之後,父子程序各自關閉不需要的檔案描述符。

③父子程序檔案共享圖示

unix/linux多程式程式設計2-程式控制
unix/linux多程式程式設計2-程式控制

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;

    }   

}運作結果如下

unix/linux多程式程式設計2-程式控制

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是系統調用,其他六個均為庫函數

繼續閱讀