天天看點

Linux建立程序的fork()函數

         在Linux中,fork函數的功能就是在一個程序中建立一個新的程序,目前調用fork函數的程序就是産生的新程序的父程序,新程序在以下也稱為子程序。在新程序生成之後就會在系統中開始執行。

  函數原型:其中pid_t 是一個long。

pid_t fork(void); 
           

        在父程序中,傳回值是子程序的程序ID,而在子程序中,傳回值則是0,是以可以通過判斷fork函數的傳回值來判斷目前執行的是父程序還是子程序。

        建立之後的子程序與父程序執行相同的程式段,但是擁有不同的堆棧段以及資料段,但是子程序中堆棧段和資料段都是父程序的完全複制,直到調用exec()函數簇讓子程序去執行的新的代碼,子程序就完全擁有了屬于自己的代碼段、堆棧段和資料段。

        在這個過程中,期初的Linux系統,确實是将父程序的所有記憶體進行複制産生新的程序映像,但太浪費記憶體了,是以現在并不會直接複制父程序的所有記憶體,而是子程序與父程序共享代碼段,子程序的一系列程序級清單都指向父程序的頁表,在exec()函數調用之後,再對子程序的頁表進行相應的調整,這個操作就用到了寫時複制技術(copy-on-write),也就是從這一刻起,子程序開始獨立地執行新的代碼段。

示例代碼:

pid_t childPid;
 switch(childPid = fork()) {
    case -1:
    //error
    break;
 
   case 0:
    //child process
    break;
    
    default:
    //father process comes here after fork()
}
           

       當程序建立失敗時,fork()的傳回值存放在errno中,當其為EAGAIN是,原因是程序的數目超過了目前允許建立的程序數量的最大值;當其為ENOMEM,表示記憶體不足,無法配置核心所需的資料結構空間。

       在Linux中,與fork()功能類似還有一個函數vfork(),這個函數也是建立一個程序,但是與fork()有一些不同,vfork()的設計理念是在建立新程序之後,阻塞父程序,用子程序直接執行新的代碼,并且使用父程序的記憶體,直到子程序執行完畢傳回,父程序才會繼續執行。在早期的Linux中vfork()比fork()更高效,因為vfork()不會隻會複制父程序的部分内容,但是在現在的Linux系統中,由于寫時複制技術,fork()的效率大大提高,甚至和fork()不相上下,是以盡量避免使用vfork()函數。而且由于vfork()建立的程序與父程序共享記憶體,極有可能出現各種未知的錯誤,這也是避免使用vfork()的重要原因。

繼續閱讀