fork和vfork的區別

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

發佈了30 篇原創文章 · 獲贊 5 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章