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,而列印出第二句話。于是得到了上面的運作結果。
再來看一個拷貝資料段的例子:
int cnt = 0;
{
cnt++;
printf("cnt=%d\n",cnt);
}
else
大家覺着列印出的值應該是多少呢?是不是2 呢?先來看下運作結果吧
[root@localhost fork]# ./fork2
cnt=1
I am the child process,ID is 5077
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
段錯誤
本來vfock()是共享資料段的,結果應該是2,為什麼不是預想的2 呢?先看一個知識點:
vfork 和fork 之間的另一個差別是:vfork 保證子程序先運作,在她調用exec 或exit 之
後父程序才可能被排程運作。如果在調用這兩個函數之前子程序依賴于父程序的進一步動
作,則會導緻死鎖。
這樣上面程式中的fork ()改成vfork()後,vfork ()建立子程序并沒有調用exec 或exit,
是以最終将導緻死鎖。
怎麼改呢?看下面程式:
pid = vfork();
_exit(0);
如果沒有_exit(0)的話,子程序沒有調用exec 或exit,是以父程序是不可能執行的,在子
程序調用exec 或exit 之後父程序才可能被排程運作。
是以我們加上_exit(0);使得子程序退出,父程序執行,這樣else 後的語句就會被父程序執行,
又因在子程序調用exec 或exit之前與父程序資料是共享的,是以子程序退出後把父程序的數
據段count改成1 了,子程序退出後,父程序又執行,最終就将count變成了2,看下實際
cnt=2
網上抄的一段,可以再了解了解:
為什麼會有vfork,因為以前的fork 很傻, 它建立一個子程序時,将會建立一個新的位址
空間,并且拷貝父程序的資源,而往往在子程序中會執行exec 調用,這樣,前面的拷貝工
作就是白費力氣了,這種情況下,聰明的人就想出了vfork,它産生的子程序剛開始暫時與
父程序共享位址空間(其實就是線程的概念了),因為這時候子程序在父程序的位址空間中
運作,是以子程序不能進行寫操作,并且在兒子 霸占”着老子的房子時候,要委屈老子一
下了,讓他在外面歇着(阻塞),一旦兒子執行了exec 或者exit 後,相 于兒子買了自己的
房子了,這時候就相 于分家了。