參見百度百科API說明:html
#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的另外一個特性是全部由父進程打開的描述符都被複制到子進程中。父、子進程中相同編號的文件描述符在內核中指向同一個file結構體,也就是說,file結構體的引用計數要增長。
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 呢?先來看下運行結果吧
爲何不是2 呢?由於咱們一次強調fork ()函數子進程拷貝父進程的數據段代碼段,因此
cnt++;
printf("cnt= %d\n",cnt);
return 0
將被父子進程各執行一次,可是子進程執行時使本身的數據段裏面的(這個數據段是從父進
程那copy 過來的如出一轍)count+1,一樣父進程執行時使本身的數據段裏面的count+1,
他們互不影響,與是便出現瞭如上的結果。
那麼再來看看vfork ()吧。若是將上面程序中的fork ()改爲vfork(),運行結果是什麼
樣子的呢?
原本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: }
refer:http://baike.baidu.com/view/1952900.htm