天天看點

嵌入式 fork與vfork的差別

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 後,相 于兒子買了自己的 

房子了,這時候就相 于分家了。

繼續閱讀