fork()與vfock()都是創建一個進程,那他們有什麼區別呢?總結有以下三點區別:
1. fork ():子進程拷貝父進程的數據段,代碼段
vfork ( ):子進程與父進程共享數據段
2. fork ()父子進程的執行次序不確定
vfork 保證子進程先運行,在調用exec 或exit 之前與父進程數據是共享的,在它調用exec
或exit 之後父進程纔可能被調度運行。
3. vfork ()保證子進程先運行,在她調用exec 或exit 之後父進程纔可能被調度運行。如果在
調用這兩個函數之前子進程依賴於父進程的進一步動作,則會導致死鎖。
下面通過幾個例子加以說明:
第一:子進程拷貝父進程的代碼段的例子:
- #include<sys/types.h>
- #include<unistd.h>
- #include<stdio.h>
- int main()
- {
- pid_t pid;
- pid = fork();
- if(pid<0)
- printf("error in fork!\n");
- 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());
- return 0;
- }
運行結果:
- [root@localhost fork]# gcc -o fork fork.c
- [root@localhost fork]# ./fork
- I am the child process,ID is 4711
- 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,而打印出第二句話。於是得到了上面的運行結果。
再來看一個拷貝數據段的例子:
- #include<sys/types.h>
- #include<unistd.h>
- #include<stdio.h>
- int main()
- {
- pid_t pid;
- int cnt = 0;
- pid = fork();
- if(pid<0)
- printf("error in fork!\n");
- else if(pid == 0)
- {
- cnt++;
- printf("cnt=%d\n",cnt);
- printf("I am the child process,ID is %d\n",getpid());
- }
- else
- {
- cnt++;
- printf("cnt=%d\n",cnt);
- printf("I am the parent process,ID is %d\n",getpid());
- }
- return 0;
- }
大家覺着打印出的值應該是多少呢?是不是2 呢?先來看下運行結果吧
- [root@localhost fork]# ./fork2
- cnt=1
- I am the child process,ID is 5077
- cnt=1
- 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(),運行結果是什麼
樣子的呢?
- [root@localhost fork]# gcc -o fork3 fork3.c
- [root@localhost fork]# ./fork3
- cnt=1
- I am the child process,ID is 4711
- cnt=1
- I am the parent process,ID is 4710
- 段錯誤
本來vfock()是共享數據段的,結果應該是2,爲什麼不是預想的2 呢?先看一個知識點:
vfork 和fork 之間的另一個區別是:vfork 保證子進程先運行,在她調用exec 或exit 之
後父進程纔可能被調度運行。如果在調用這兩個函數之前子進程依賴於父進程的進一步動
作,則會導致死鎖。
這樣上面程序中的fork ()改成vfork()後,vfork ()創建子進程並沒有調用exec 或exit,
所以最終將導致死鎖。
怎麼改呢?看下面程序:
- #include<sys/types.h>
- #include<unistd.h>
- #include<stdio.h>
- int main()
- {
- pid_t pid;
- int cnt = 0;
- pid = vfork();
- if(pid<0)
- printf("error in fork!\n");
- else if(pid == 0)
- {
- cnt++;
- printf("cnt=%d\n",cnt);
- printf("I am the child process,ID is %d\n",getpid());
- _exit(0);
- }
- else
- {
- cnt++;
- printf("cnt=%d\n",cnt);
- printf("I am the parent process,ID is %d\n",getpid());
- }
- return 0;
- }
如果沒有_exit(0)的話,子進程沒有調用exec 或exit,所以父進程是不可能執行的,在子
進程調用exec 或exit 之後父進程纔可能被調度運行。
所以我們加上_exit(0);使得子進程退出,父進程執行,這樣else 後的語句就會被父進程執行,
又因在子進程調用exec 或exit之前與父進程數據是共享的,所以子進程退出後把父進程的數
據段count改成1 了,子進程退出後,父進程又執行,最終就將count變成了2,看下實際
運行結果:
- [root@localhost fork]# gcc -o fork3 fork3.c
- [root@localhost fork]# ./fork3
- cnt=1
- I am the child process,ID is 4711
- cnt=2
- I am the parent process,ID is 4710
網上抄的一段,可以再理解理解:
爲什麼會有vfork,因爲以前的fork 很傻, 它創建一個子進程時,將會創建一個新的地址
空間,並且拷貝父進程的資源,而往往在子進程中會執行exec 調用,這樣,前面的拷貝工
作就是白費力氣了,這種情況下,聰明的人就想出了vfork,它產生的子進程剛開始暫時與
父進程共享地址空間(其實就是線程的概念了),因爲這時候子進程在父進程的地址空間中
運行,所以子進程不能進行寫操作,並且在兒子 霸佔”着老子的房子時候,要委屈老子一
下了,讓他在外面歇着(阻塞),一旦兒子執行了exec 或者exit 後,相 於兒子買了自己的
房子了,這時候就相 於分家了。