1. 程式人生 > >程式設計師必備知識——fork和exec函式詳解

程式設計師必備知識——fork和exec函式詳解

        在學習UNIX程式設計時,必須要學習的一個函式為fork函式。fork函式也為面試中必定要問的一個問題,尤其是在BAT的面試中,fork函式相關問題更為面試筆試必考知識點。究其原因:該函式為UNIX中派生新程序的唯一方法。不熟悉fork,就不可能熟悉多執行緒程式設計。因此掌握好fork函式,為程式設計師和準程式設計師必備技能。

1 fork函式原型

<pre name="code" class="cpp">#include<unistd.h>
pid_t fork(void);</span>
返回:在子程序中返回0,在父程序中返回子程序的id,出錯返回-1.
        如果之前從未接觸過這個函式,那麼理解fork函式的最困難之處在於呼叫它一次,它卻返回兩次它在呼叫程序(成為父程序)中返回一次,返回值為新派生程序(成為子程序)的程序ID號;在子程序中又返回一次,返回值為0.因此,返回值本身告知當前程序是子程序還是父程序。
        fork在子程序中返回0而不是父程序的ID的原因在於:任何子程序只有一個父程序,而且子程序總是可以通過呼叫getppid取得父程序的ID。相反,父程序可以有許多子程序,而且無法獲得各個子程序的程序ID。如果父程序想要跟蹤所有子程序的ID,那麼它必須記錄每次呼叫fork的返回值。

        父程序中呼叫fork之前開啟所有的描述字在fork返回之後由子程序分享。我們將看到網路伺服器便利用了這個特性:父程序呼叫accept之後呼叫fork。所接受的已連線的套介面隨後就在父程序與子程序之間分享。通常情況下,子程序接著讀和寫這個套介面,父程序則關閉這個已連線套介面。

2 fork用法

        fork有兩個典型的用法:
        1 一個程序建立一個自身的拷貝,這樣每個拷貝都可以在另一個拷貝執行其他任務的同時處理各自的某個操作。這是網路伺服器的典型用法。
        2 一個程序想要執行另一個程式。既然建立新程序的唯一方法為呼叫fork,該程序於是首先呼叫fork建立一個自身的拷貝,然後其中一個拷貝(通常為子程序)呼叫exec把自身替換成新的程式。這是諸如shell之類程式的典型用法。

3 exec函式

        存放在硬碟上的可執行檔案能夠被UNIX執行的唯一方法是:由一個現有程序呼叫六個exec函式中的某一個。exec把當前程序映像替換成新的程序檔案,而且該新程式通常從main函式處開始執行。程序ID並不改變。我們稱呼叫exec的程序為呼叫程序,稱新執行的程式為新程式。

        六個exec函式的區別在於:(a)待執行的程式檔案是由檔名還是由路徑名指定;(b)新程式的引數是一一列出還是由一個指標陣列來引用;(c)把呼叫程序的環境傳遞給新程式還是給新程式指定新的環境。

---------------------------------------------------------------------------
|#include<unistd.h>
|int execl(const char *pathname, const char *arg0,.../* (char *)0 */);
|int execv(const char *pathname, char *const argv[]);
|int execle(const char *pathname, const char *arg0,.../* (char *)0,char *const envp[] */);
|int execve(const char *pathname, char *const argv[], char *const envp[]);
|int execlp(const char *filename, const char *arg0,.../* (char *)0 */);
|int execvp(const char *filename, char *const argv[]);
|所有六個函式返回:-1——失敗,無返回——成功
----------------------------------------------------------------------------

         這些函式只在出錯時才返回到呼叫者。否則,控制將傳遞給新程式的起始點,通常就是main函式。
這六個函式之間的關係如下圖所示。一般來說,只有 execve 是核心中的系統呼叫,其他五個都是呼叫 execve 的庫函式。


注意這六個函式的下列區別
        1 頂行三個函式把新程式的每個引數字串指定成exec的一個獨立引數,並以一個空指標結束可變數量的這些引數。底行三個函式都有一個作為exec引數的argv陣列,其中含有指向新程式各個引數字串的所有指標。既然沒有指定引數字串的數目,這個argv陣列必須含有一個用於指定其末尾的空指標。
        2 左列兩個函式指定一個filename引數。exec將使用當前的PATH環境變數把該檔名引數轉換為一個路徑名。然而如果這兩個函式的filename引數中不論何處含有一個斜槓(/),PAHT變數就不再使用。右兩列四個函式指定一個全限定的pathname引數。
        3 左兩列四個函式不顯式指定一個環境指標。相反,他們使用外部變數environ的當前值來構造一個傳遞給新程式的環境清單。右列兩個函式顯式指定一個環境清單,其envp指標陣列必須以一個空指標結束。