fork()和vfork()都是創建一個進程,區別在於:
fork():子進程拷貝父進程的數據段和代碼段,且父子進程的執行順序是不確定的
vfork():共享父進程的數據段,確保子進程優先執行,在調用exec或exit之前與父進程共享數據段,在調用exec或exit父進程纔可能被調度運行。如果在調用這兩個函數之前,子進程依賴於父進程的進一步動作,則會造成死鎖。
舉例如下:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
void main()
{
pid_t pid;
pid = fork();
if(pid < 0)
{
printf("process create error!/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());
}
}
#gcc fork1.c -o fork1
# ./fork1
I am the parent process,ID is 4237
I am the child process,ID is 4238
因爲fork()用於從一個已存在的進程中,創建一個新的進程。新的進程爲子進程,原來的進程爲父進程。fork()的返回值有兩個,子進程返回0,父進程返回子進程的進程號,進程號都是非零的整數。在調用pid=fork()之前,只有父進程在運行,而在pid=fork()之後,父子進程都在運行。pid==0則是子進程,pid!=0則是父進程。我們知道fork()在創建進程時,會拷貝父進程的數據段和代碼段,所以子進程中也包含了一下代碼:
if(pid < 0){
printf("process create error!/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());
}
以上代碼在父子進程中個執行一次,所以打印兩條語句。
例子:
void main()
{
int count = 0;
pid_t pid;
pid = fork();
count++;
printf("count is %d/n",count);
return 0;
}
# gcc fork2.c -o fork2
# ./fork2
count= 1
count= 1
這裏count爲什麼不是2呢?再強調一次,fork()函數中的子進程拷貝父進程的數據段和代碼段。所以
count++;
printf("count is %d/n",count);
在父子進程中各執行一次,但子進程使用的是自己的數據段(這和從父進程中拷貝過來的一模一樣)。它們互不影響。
接下來分析vfork()
將上述程序的fork()換成vfork(),結果如下:
count is 1
count is -1210017386
段錯誤
本來vfock()是共享數據段的,結果應該是 2,爲什麼不是預想的 2 呢?
知識點:vfrok與fork的一個區別就是vfork保證子進程優先執行,在他調用exec或則exit之後,父進程纔可能被調度執行。如果調用者兩個函數之前,子進程依賴於父進程的進一步動作則會死鎖。將程序做如下修改:
int main()
{
pid_t pid;
int count =0;
pid = vfork();
if(pid == 0){
count ++;
_exit(0);
}else{
count++
printf("the count is %d/n",count);
}
return 0;
}
結果:
count is 2
如果沒有_exit(0)的話,子進程沒有調用 exec或 exit,所以父進程是不可能執行的,在子進程調用exec或exit 之後父進程纔可能被調度運行。 所以我們加上_exit(0);使得子進程退出,父進程執行,這樣 else後的語句就會被父進程執行,又因在子進程調用exec或exit之前與父進程數據是共享的,所以子進程退出後把父進程的數據段count改成1了,子進程退出後,父進程又執行,最終就將count 變成了2
爲什麼會有vfork,因爲以前的fork很傻,當它創建一個子進程時,將會創建一個新的地址空間,並且拷貝父進程的資源,而往往在子進程中會執行 exec 調用,這樣,前面的拷貝工作就是白費力氣了,這種情況下,聰明的人就想出了 vfork,它產生的子進程剛開始暫時與父進程共享地址空間(其實就是線程的概念了),因爲這時候子進程在父進程的地址空間中運行,所以子進程不能進行寫操作,並且在兒子“ 霸佔”着老子的房子時候,要委屈老子一下了,讓他在外面歇着(阻塞) ,一旦兒子執行 了 exec或者 exit後,相當於兒子買了自己的房子了,這時候就相當於分家了。
pid: current->pid
cpu: smp_processor_id()
command: current->comm
轉自:http://blog.csdn.net/lijierson8/archive/2010/10/11/5932764.aspx