關於vfork的小知識

介紹

vfork和fork一樣都可以用來創建一個新進程,與fork相比,它有一些自己獨特的用處。下面是他們的一些異同
* vfork 與fork一樣都是調用一次,返回兩次(一個是父進程調用vfork後的返回值,該返回值爲子進程的pid。一個是子進程調用vfork的返回值,該返回值爲0)
* 使用fork創建一個子進程的時候,子進程只是完整複製子進程的資源。這樣得到的子進程獨立於父進程,具有良好的併發性。而使用vfork創建子進程時,操作系統並不將父進程的地址空間完全複製到子進程,用vfork創建的子進程共享父進程的地址空間,也就是說子進程完全運行在父進程的地址空間上。子進程對該地址空間中任何數據的修改同樣爲父進程所見。
* 使用fork創建一個子進程時,哪個進程先運行取決於系統的調度算法。而vfork一個進程時,vfork保證子進程先運行,當它調用exec或exit後,父進程纔可以被調度運行。如果在調用exec或exit之前子進程要依賴父進程的某幾個行爲,就會導致死鎖。
fork創建一個子進程時,子進程要將父進程幾乎每種資源都複製,所以fork是一個開銷很大的系統調用,這些開銷並不是所有情況都適用。比如fork一個進程後,立即調用exec執行另一個應用程序,那麼fork過程中子進程對父進程地址空間的複製將是一個多餘的過程。vfork不會拷貝父進程的地址空間,大大減少了系統開銷。
我們看看下面這段程序。

代碼

fork

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>

int qvar=5;

int main()
{   
    pid_t pid;
    int var=1,i;
    char str[]="I'm here";

    printf("fork is different with vfork\n");

    pid=fork();
    //pid=vfork();
    switch(pid)
    {
        case 0:
            i=3;
            while(i--)
            {
                printf("Child process is running\n");
                qvar++;
                var++;
                sleep(1);
            }

            printf("Child's qvar = %d,var = %d,str = %s\n",qvar,var,str);
            exit(0);
            break;
        case -1:
            perror("failed\n");
            exit(0);
            break;
        default:
            i=5;
            while(i-->0)
            {
                printf("Parent is running\n");
                qvar++;
                var++;
                sleep(1);
            }
            printf("Parent's qvar = %d,var = %d,str = %s\n",qvar,var);
            exit(0);
    }
}

fork結果

這裏寫圖片描述

分析

可見用fork創建子進程時,子進程繼承了父進程的全劇變量和局部變量。而且根據子進程的qvar,var均增加了3。父進程的qvar,var也增加了3.且兩者的值並未影響可知父子進程有各自獨立的地址空間。

我們將上面vfork的註釋去掉,然後再註釋調fork。

vfork結果

這裏寫圖片描述

分析

首先可見子進程要先於父進程運行,並且由qvar,var的值遞增了8可見,vfork後子進程和父進程共享了一段地址空間。

注意

如果我們將vfork下子進程的exit(0)去掉,那麼我們看看會發生什麼情況
這裏寫圖片描述
我們可以看到父進程的var成了隨機值,str也找不到了。
這是因爲vfork是這樣的工作的:
(1)、保證子進程先執行。
(2)、當子進程調用exit()或exec()後,父進程往下執行。
當去掉子子進程下的exit後,程序默認return。而return會將棧釋放,因此當子進程執行完,回到父進程時,父進程的棧已被子進程釋放掉了(這就是赤裸裸的坑爹!),因此var爲隨機值。
因此當我們使用vfork時一定記得在子進程結束後用exit結束,不然會出現一些意想不到的結果。關於這點可以參考
用return和exit結束fork和vfork創建的子進程的思考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章