vfork與fork區別 轉載

fork()與vfock()都是創建一個進程,那他們有什麼區別呢?總結有以下三點區別: 
1.  fork  ():子進程拷貝父進程的數據段,代碼段 
    vfork ( ):子進程與父進程共享數據段 
2.  fork ()父子進程的執行次序不確定 
    vfork 保證子進程先運行,在調用exec 或exit 之前與父進程數據是共享的,在它調用exec
     或exit 之後父進程纔可能被調度運行。 
3.  vfork ()保證子進程先運行,在她調用exec 或exit 之後父進程纔可能被調度運行。如果在
   調用這兩個函數之前子進程依賴於父進程的進一步動作,則會導致死鎖。 
下面通過幾個例子加以說明: 
第一:子進程拷貝父進程的代碼段的例子: 

  1. #include<sys/types.h>  
  2. #include<unistd.h>  
  3. #include<stdio.h>  
  4.   
  5. int main()  
  6. {  
  7.     pid_t pid;  
  8.     pid = fork();  
  9.     if(pid<0)  
  10.         printf("error in fork!\n");  
  11.     else if(pid == 0)  
  12.         printf("I am the child process,ID is %d\n",getpid());  
  13.     else   
  14.         printf("I am the parent process,ID is %d\n",getpid());  
  15.     return 0;  
  16.   
  17. }  


運行結果: 

  1. [root@localhost fork]# gcc -o fork fork.c   
  2. [root@localhost fork]# ./fork  
  1. I am the child process,ID is 4711  
  2. I am the parent process,ID is 4710  


爲什麼兩條語 都會打印呢?這是因爲fork()函數用於從已存在的進程中創建一個新的進 
程,新的進程稱爲子進程,而原進程稱爲父進程,fork ()的返回值有兩個,子進程返回0,
父進程返回子進程的進程號,進程號都是非零的正整數,所以父進程返回的值一定大於零,
在pid=fork();語句之前只有父進程在運行,而在pid=fork();之後,父進程和新創建的子進程 
都在運行,所以如果pid==0,那麼肯定是子進程,若pid !=0 (事實上肯定大於0),那麼是 
父進程在運行。而我們知道fork()函數子進程是拷貝父進程的代碼段的,所以子進程中同樣 
有 
if(pid<0) 
         printf("error in fork!"); 
     else if(pid==0) 
         printf("I am the child process,ID is %d\n",getpid()); 
     else 
         printf("I am the parent process,ID is %d\n",getpid()); 

這麼一段代碼,所以上面這段代碼會被父進程和子進程各執行一次,最終由於子進程的pid= =0,

而打印出第一句話,父進程的pid>0,而打印出第二句話。於是得到了上面的運行結果。 
再來看一個拷貝數據段的例子: 

  1. #include<sys/types.h>  
  2. #include<unistd.h>  
  3. #include<stdio.h>  
  4.   
  5. int main()  
  6. {  
  7.     pid_t pid;  
  8.     int cnt = 0;  
  9.     pid = fork();  
  10.     if(pid<0)  
  11.         printf("error in fork!\n");  
  12.     else if(pid == 0)  
  13.     {  
  14.         cnt++;  
  15.         printf("cnt=%d\n",cnt);  
  16.         printf("I am the child process,ID is %d\n",getpid());  
  17.     }  
  18.     else  
  19.     {  
  20.         cnt++;  
  21.         printf("cnt=%d\n",cnt);  
  22.         printf("I am the parent process,ID is %d\n",getpid());  
  23.     }  
  24.     return 0;  
  25. }  

 

大家覺着打印出的值應該是多少呢?是不是2 呢?先來看下運行結果吧 

  1. [root@localhost fork]# ./fork2  
  2. cnt=1  
  3. I am the child process,ID is 5077  
  4. cnt=1  
  5. I am the parent process,ID is 5076  

 

爲什麼不是2 呢?因爲我們一次強調fork ()函數子進程拷貝父進程的數據段代碼段,所以 
cnt++; 
    printf("cnt= %d\n",cnt);

    return 0 
將被父子進程各執行一次,但是子進程執行時使自己的數據段裏面的(這個數據段是從父進 
程那copy 過來的一模一樣)count+1,同樣父進程執行時使自己的數據段裏面的count+1, 
他們互不影響,與是便出現瞭如上的結果。


那麼再來看看vfork ()吧。如果將上面程序中的fork ()改成vfork(),運行結果是什麼 
樣子的呢? 

  1. [root@localhost fork]# gcc -o fork3 fork3.c   
  2. [root@localhost fork]# ./fork3  
  3. cnt=1  
  4. I am the child process,ID is 4711  
  5. cnt=1  
  6. I am the parent process,ID is 4710  
  7. 段錯誤  

 

本來vfock()是共享數據段的,結果應該是2,爲什麼不是預想的2 呢?先看一個知識點: 
vfork 和fork 之間的另一個區別是:vfork 保證子進程先運行,在她調用exec 或exit 之 
後父進程纔可能被調度運行。如果在調用這兩個函數之前子進程依賴於父進程的進一步動 
作,則會導致死鎖。 
這樣上面程序中的fork ()改成vfork()後,vfork ()創建子進程並沒有調用exec 或exit,
所以最終將導致死鎖。 
怎麼改呢?看下面程序: 

  1. #include<sys/types.h>  
  2. #include<unistd.h>  
  3. #include<stdio.h>  
  4.   
  5. int main()  
  6. {  
  7.     pid_t pid;  
  8.     int cnt = 0;  
  9.     pid = vfork();  
  10.     if(pid<0)  
  11.         printf("error in fork!\n");  
  12.     else if(pid == 0)  
  13.     {  
  14.         cnt++;  
  15.         printf("cnt=%d\n",cnt);  
  16.         printf("I am the child process,ID is %d\n",getpid());  
  17.        _exit(0);  
  18.     }  
  19.     else  
  20.     {  
  21.         cnt++;  
  22.         printf("cnt=%d\n",cnt);  
  23.         printf("I am the parent process,ID is %d\n",getpid());  
  24.     }  
  25.     return 0;  
  26.   
  27. }  


 

如果沒有_exit(0)的話,子進程沒有調用exec 或exit,所以父進程是不可能執行的,在子 
進程調用exec 或exit 之後父進程纔可能被調度運行。 
所以我們加上_exit(0);使得子進程退出,父進程執行,這樣else 後的語句就會被父進程執行, 
又因在子進程調用exec 或exit之前與父進程數據是共享的,所以子進程退出後把父進程的數 
據段count改成1 了,子進程退出後,父進程又執行,最終就將count變成了2,看下實際 
運行結果: 

  1. [root@localhost fork]# gcc -o fork3 fork3.c   
  2. [root@localhost fork]# ./fork3  
  3. cnt=1  
  4. I am the child process,ID is 4711  
  5. cnt=2  
  6. I am the parent process,ID is 4710  

 

網上抄的一段,可以再理解理解: 
爲什麼會有vfork,因爲以前的fork 很傻, 它創建一個子進程時,將會創建一個新的地址 
空間,並且拷貝父進程的資源,而往往在子進程中會執行exec 調用,這樣,前面的拷貝工 
作就是白費力氣了,這種情況下,聰明的人就想出了vfork,它產生的子進程剛開始暫時與 
父進程共享地址空間(其實就是線程的概念了),因爲這時候子進程在父進程的地址空間中 
運行,所以子進程不能進行寫操作,並且在兒子 霸佔”着老子的房子時候,要委屈老子一 
下了,讓他在外面歇着(阻塞),一旦兒子執行了exec 或者exit 後,相 於兒子買了自己的 
房子了,這時候就相 於分家了。

                                     


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