fork和vfork的區別

參見百度百科API說明:html

fork

頭文件:

#include<unistd.h>app

#include<sys/types.h>函數

函數原型:

pid_t fork( void);spa

(pid_t 是一個宏定義,其實質是int 被定義在#include<sys/types.h>中).net

返回值: 若成功調用一次則返回兩個值,子進程返回0,父進程返回子進程ID;不然,出錯返回-13d

函數說明:

一個現有進程能夠調用fork函數建立一個新進程。由fork建立的新進程被稱爲子進程(child process)。fork函數被調用一次但返回兩次。兩次返回的惟一區別是子進程中返回0值而父進程中返回子進程ID。code

子進程是父進程的副本,它將得到父進程數據空間、堆、棧等資源的副本。注意,子進程持有的是上述存儲空間的「副本」,這意味着父子進程間不共享這些存儲空間。htm

UNIX將複製父進程地址空間內容給子進程,所以,子進程有了獨立的地址空間。在不一樣的UNIX (Like)系統下,咱們沒法肯定fork以後是子進程先運行仍是父進程先運行,這依賴於系統的實現。因此在移植代碼的時候咱們不該該對此做出任何的假設。blog

爲何fork會返回兩次?

因爲在複製時複製了父進程堆棧段,因此兩個進程都停留在fork函數中,等待返回。所以fork函數會返回兩次,一次是在父進程中返回,另外一次是在子進程中返回,這兩次的返回值是不同的。過程以下圖進程

調用fork以後,數據、堆棧有兩份,代碼仍然爲一份可是這個代碼段成爲兩個進程的共享代碼段都從fork函數中返回,箭頭表示各自的執行處。當父子進程有一個想要修改數據或者堆棧時,兩個進程真正分裂。

fork函數的特色歸納起來就是「調用一次,返回兩次」,在父進程中調用一次,在父進程和子進程中各返回一次。

fork的另外一個特性是全部由父進程打開的描述符都被複制到子進程中。父、子進程中相同編號的文件描述符內核中指向同一個file結構體,也就是說,file結構體的引用計數要增長。

vfork

vfork(創建一個新的進程)

相關函數wait,execve

頭文件 #include<unistd.h>

定義函數pid_t vfork(void);

vfork()會產生一個新的子進程.可是vfork建立的子進程與父進程共享數據段,並且由vfork建立的

子進程將先於父進程運行.fork()的使用詳見百度詞條fork().

vfork()用法與fork()類似.可是也有區別,具體區別歸結爲如下3點:

1. fork():子進程拷貝父進程的數據段,代碼段. vfork():子進程與父進程共享數據段.

2. fork():父子進程的執行次序不肯定.

vfork():保證子進程先運行,在調用exec或exit以前與父進程數據是共享的,在它調用exec

或exit以後父進程纔可能被調度運行。

3. vfork()保證子進程先運行,在她調用exec或exit以後父進程纔可能被調度運行。若是在

調用這兩個函數以前子進程依賴於父進程的進一步動做,則會致使死鎖。

4.當須要改變共享數據段中變量的值,則拷貝父進程。

我的理解:
fork和vfork均可以用來建立子進程.fork建立子進程後,父子進程的數據段和堆棧段分離,會產生複製消耗資源.而在實際的應用中,有時是不須要的.好比子進程建立後就執行exec調用了.這樣就產生了vfork,其產生的子進程和父進程共享數據段. 同時fork建立的子進程和父進程的運行的前後順序是沒有保證的,便可能父進程先運行,也可能子進程先運行.而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: }  

運行結果:

cnt=1
I am the child process,ID is 2164
cnt=1
I am the parent process,ID is 2163

爲何兩條語 都會打印呢?這是由於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. cnt=1  
  2. I am the child process,ID is 4711  
  3. cnt=1  
  4. I am the parent process,ID is 4710  
  5. 段錯誤 

原本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 

 

refer:http://baike.baidu.com/view/1952900.htm

         http://baike.baidu.com/view/1745340.htm

         http://blog.csdn.net/jianchi88/article/details/6985326

相關文章
相關標籤/搜索