應該看兩遍!
          1. #include <sys/types.h>   
          2. #include <unistd.h>   
          3. /* 
          4. 功能:復制進程 
          5. 參數:無 
          6. 返回值:  成功:  父進程:返回子進程id 
          7.                 子進程:返回0 
          8.          失敗:  返回-1 
          9. */  
          10. 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例子

           

          1. #include <unistd.h>   
          2. #include <sys/types.h>   
          3. #include <stdio.h>   
          4. int main(void)  
          5. {  
          6.     pid_t pid;  
          7.     pid=fork();  
          8.     switch (pid)  
          9.     {  
          10.     case -1:  
          11.         perror("fork error");  
          12.         exit(1);  
          13.     case 0:  
          14.         printf("I am the child process, my process id is %d/n", getpid());  
          15.         break;  
          16.     default:  
          17.         printf("I am the parent process, my process id is %d/n", getpid());  
          18.         break;  
          19.     }  
          20.      return 0;  
          21. }   

           

          要搞清楚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...)不可預見,與操作系統實際運行情況有關!

          posted on 2012-07-26 11:51 姚先進 閱讀(182) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
           
          主站蜘蛛池模板: 正蓝旗| 巩义市| 邹平县| 彭泽县| 阿巴嘎旗| 城步| 定襄县| 临澧县| 舒城县| 竹溪县| 手游| 开原市| 鲁山县| 芮城县| 呼玛县| 义乌市| 师宗县| 米脂县| 娱乐| 安西县| 东乡族自治县| 开封市| 永安市| 永丰县| 右玉县| 库尔勒市| 井陉县| 岳池县| 新干县| 冕宁县| 巢湖市| 贡嘎县| 文成县| 郁南县| 新民市| 丽水市| 长垣县| 桃源县| 西平县| 孟村| 正镶白旗|