標籤:style color 使用 資料 art io
#include <sys/types.h>#include <unistd.h>/*功能:複製進程參數:無傳回值: 成功: 父進程:返回子進程id 子進程:返回0 失敗: 返回-1*/pid_t fork(void);
由fork建立的新進程被稱為子進程(child process)。該函數被調用一次,但返回兩次。兩次返回的差別是子進程的傳回值是0,而父進程的傳回值則是新進程(子進程)的進程 id。將子進程id返回給父進程的理由是:由於一個進程的子進程能夠多於一個,沒有一個函數使一個進程能夠獲得其全部子進程的進程id。對子進程來說,之所以fork返回0給它,是由於它隨時能夠調用getpid()來擷取自己的pid;也能夠調用getppid()來擷取父進程的id。(進程id 0總是由交換進程使用,所以一個子進程的進程id不可能為0 )。
fork之後,作業系統會複製一個與父進程全然同樣的子進程,雖說是父子關係,可是在作業系統看來,他們更像兄弟關係,這2個進程共用代碼空間,可是資料空間是互相獨立的,子進程資料空間中的內容是父進程的完整拷貝,指令指標也全然同樣,子進程擁有父進程當前執行到的位置(兩進程的程式計數器pc值同樣,也就是說,子進程是從fork返回處開始執行的),但有一點不同,假設fork成功,子進程中fork的傳回值是0,父進程中fork的傳回值是子進程的進程號,假設fork不成功,父進程會返回錯誤。
能夠這樣想象,2個進程一直同一時候執行,並且步調一致,在fork之後,他們分別作不同的工作,也就是分岔了。這也是fork為什麼叫fork的原因
至於那一個最先執行,可能與作業系統(調度演算法)有關,並且這個問題在實際應用中並不重要,假設須要父子進程協同,能夠通過原語的辦法解決。
一個fork範例
#include <unistd.h>#include <sys/types.h>#include <stdio.h>int main(void){pid_t pid;pid=fork();switch (pid){case -1:perror("fork error");exit(1);case 0:printf("I am the child process, my process id is %d/n", getpid());break;default:printf("I am the parent process, my process id is %d/n", getpid());break;} return 0;}
要搞清楚fork的運行過程,就必須先弄清楚作業系統中的“進程(process)”概念。一個進程,主要包括三個元素:
o. 一個能夠啟動並執行程式;
o. 和該進程相關聯的所有資料(包含變數,記憶體空間,緩衝區等等);
o. 程式的運行上下文(execution context)。
最好還是簡單理解為,一個進程表示的,就是一個可運行程式的一次運行過程中的一個狀態。作業系統對進程的管理,典型的情況,是通過進程表完畢的。進程表中的每個表項,記錄的是當前作業系統中一個進程的情況。對於單 CPU的情況而言,每一特定時刻僅僅有一個進程佔用 CPU,可是系統中可能同一時候存在多個活動的(等待運行或繼續啟動並執行)進程。
一個稱為“程式計數器(program counter, pc)”的寄存器,指出當前佔用 CPU的進程要啟動並執行下一條指令的位置。
當分給某個進程的 CPU時間已經用完,作業系統將該進程相關的寄存器的值,儲存到該進程在進程表中相應的表項裡面;把將要接替這個進程佔用 CPU的那個進程的上下文,從進程表中讀出,並更新相應的寄存器(這個過程稱為“上下文交換(process context switch)”,實際的上下文交換須要涉及到很多其它的資料,那和fork無關,不再多說,主要要記住程式寄存器pc記錄了程式當前已經運行到哪裡,是進程內容相關的重要內容,換出 CPU的進程要儲存這個寄存器的值,換入CPU的進程,也要依據進程表中儲存的本進程運行上下文資訊,更新這個寄存器)。
好了,有這些概念打底,能夠說fork了。當你的程式運行到以下的語句:pid=fork();
作業系統建立一個新的進程(子進程),而且在進程表中對應為它建立一個新的表項。新進程和原有進程的可運行程式是同一個程式;上下文和資料,絕大部分就是原進程(父進程)的拷貝,但它們是兩個相互獨立的進程!此時程式寄存器pc,在父、子進程的上下文中都聲稱,這個進程眼下運行到fork調用即將返回(此時子進程不佔有CPU,子進程的pc不是真正儲存在寄存器中,而是作為進程上下文儲存在進程表中的相應表項內)。問題是怎麼返回,在父子進程中就分道揚鑣。
(如果父進程一直佔領CPU,實際情況非常可能不一樣)父進程繼續運行,作業系統對fork的實現,使這個調用在父進程中返回剛剛建立的子進程的pid(一個正整數),所以以下的swtich語句中運行了default分支(case -1,case 0分支都不滿足)。所以輸出I am the parent process...
子進程在之後的某個時候得到調度,它的上下文被換入,佔領 CPU,作業系統對fork的實現,使得子進程中fork調用返回0,所以在這個進程(注意這不是父進程了哦,儘管是同一個程式,可是這是同一個程式的另外一次運行,在作業系統中這次運行是由另外一個進程表示的,從啟動並執行角度說和父進程相互獨立)中pid=0。這個進程繼續啟動並執行過程中,switch語句中 case -1不滿足,可是case 0是滿足。所以輸出I am the child process..
程式的執行結果(先輸出I am the parent process...,還是I am the parent process...)不可預見,與作業系統實際執行情況有關!