linux下 fork題 轉

Linux下fork()函數淺析

實驗環境:Ubuntu  3.5.0-32-generic

頭文件:

        #include <unistd.h>

        #include <sys/types.h>

函數原型:

 pid_t fork(void);
(pid_t 是一個宏定義,其實質是int 被定義在#include<sys/types.h>中)
返回值: 若成功調用一次則返回兩個值,子進程返回0,父進程返回子進程ID;否則,出錯返回-1

     fork()函數通過系統調用創建一個與原來進程幾乎完全相同的進程,也就是兩個進程可以做完全相同的事,但如果初始參數或者傳入的變量不同,兩個進程也可以做不同的事。

     一個進程調用fork()函數後,系統先給新的進程分配資源,例如存儲數據和代碼的空間。然後把原來的進程的所有值都複製到新的新進程中,只有少數值與原來的進程的值不同。相當於克隆了一個自己。當子進程被調度得以執行時,其從程序中fork()語句下一條指令開始執行。

     由fork創建的新進程被稱爲子進程(child process)。該函數被調用一次,但返回兩次。兩次返回的區別是子進程的返回值是0,而父進程的返回值則是新進程(子進程)的進程 id。將子進程id返回給父進程的理由是:因爲一個進程的子進程可以多於一個,沒有一個函數使一個進程可以獲得其所有子進程的進程id。 對子進程來說,之所以fork返回0給它,是因爲它隨時可以調用getpid()來獲取自己的pid;也可以調用getppid()來獲取父進程的id。(進程id 0總是由交換進程使用,所以一個子進程的進程id不可能爲0 )。

Program1:

  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include <sys/types.h>  
  4. #include <unistd.h>  
  5.   
  6. int main(int argc,char * argv[])  
  7. {  
  8.     pid_t pid = 0;  
  9.   
  10.     printf("Before fork!--with \"\\n\"\n");  
  11.     printf("Before fork!--without \"\\n\"");  
  12.   
  13.     pid = fork();  
  14.   
  15.     if(pid == 0){  
  16.         printf("Child process!\n");  
  17.         pid_t pid_child = getpid();  
  18.         printf("Pid = %d\n",pid_child);  
  19.     }  
  20.   
  21.     else if(pid > 0){  
  22.         printf("Parent process!\n");  
  23.         pid_t pid_parent = getpid();  
  24.         printf("Pid = %d\n",pid_parent);  
  25.     }  
  26.   
  27.     else{  
  28.         printf("fork failure!\n");  
  29.     }  
  30.   
  31.     exit(0);  
  32. }  

Output:

程序淺析:

        在父進程中利用fork()系統調用生成子進程,此時父進程pid_parent = 3804,子進程pid_child = 3805;生成子進程後,父進程繼續執行輸出父進程pid,到遇見exit(0)後父進程退出,並退出Linux控制檯。調度函數調度執行子進程,子進程在從程序fork語句下一語句開始執行,輸出子進程pid,直到遇見exit(0)結束。

        在程序中字符串"Before fork!--with "\n""與字符串"Before fork--without "\n""的輸出語句均在原程序中fork語句前執行,但前者只在父進程中輸出一次,而後者在父、子進程都有輸出一次,主要在於輸出語句“printf”的實現中對輸出緩存的處理,輸出語句中的換行符"\n"會強制刷新輸出緩存,故帶換行符的輸出語句只在父進程中輸出一次,而後者在父進程結束後仍在輸出緩存中保存,在子進程執行至輸出語句printf("Child process!\n")時一併輸出。

Program2:

  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include <sys/types.h>  
  4. #include <unistd.h>  
  5.   
  6. int main(int argc,char * argv[])  
  7. {  
  8.     pid_t pid = 0;  
  9.     int count = 13;  
  10.   
  11.     pid = fork();  
  12.   
  13.     if(pid == 0){  
  14.         sleep(1);  
  15.         count = 31;  
  16.         printf("Child process!\nPid = %d\n",getpid());  
  17.     }  
  18.       
  19.     else if(pid > 0){  
  20.         wait(NULL);  
  21.         printf("Parent process!\nPid = %d\n",getpid());  
  22.     }  
  23.   
  24.     else{  
  25.         printf("Fork error!\n");  
  26.     }  
  27.   
  28.     printf("There are %d apples!\n",count);  
  29.   
  30.     exit(0);  
  31. }  
Output:


        wait()會暫時停止目前進程的執行,直到有信號來到或子進程結束。如果在調用wait()時子進程已經結束,則wait()會立即返回子進程結束狀態值。子進程的結束狀態值會由參數status 返回,而子進程的進程識別碼也會一快返回。如果不在意結束狀態值,則參數status 可以設成NULL。

        在本程序中,父進程調用fork()函數創建子進程3837後,父進程繼續執行,當執行到wait(NULL);時,阻塞自己,調度函數調度子進程開始執行,子進程結束後,父進程從阻塞前的地方開始繼續執行,此時子進程對count值的改變並未傳遞至父進程,輸出count值,直到exit(0)結束。


Program 3:

  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include <sys/types.h>  
  4. #include <unistd.h>  
  5.   
  6. int main(int argc,char * argv[])  
  7. {  
  8.     fork();  
  9.     fork()&&fork()||fork();  
  10.     fork();  
  11.     exit(0);  
  12. }  

以上程序共有多少個進程?


共創建19個新進程,與父進程一共20個進程。

我們對以上程序作一些修改,讓每個進程執行均有一個標誌性的輸出,即可驗證我們的猜想!

Program 3‘:

  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include <sys/types.h>  
  4. #include <unistd.h>  
  5.   
  6. int main(int argc,char *argv[])  
  7. {  
  8.     fork();  
  9.     fork() && fork() || fork();  
  10.     fork();  
  11.   
  12.     printf("End of process!\n");  
  13.     exit(0);  
  14. }  
Output:


           由以上程序可見,共執行輸出語句20次,即我們的分析得以驗證:共20個進程。

        *由於某些原因,先前所用Ubuntu系統故障,此程序在centos平臺完成測試。 

附錄:

        wait()與waitpid()淺析

        sleep()系統調用淺析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章