歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> 學習Linux >> Linux之fork與vfork區別

Linux之fork與vfork區別

日期:2017/3/6 9:27:08   编辑:學習Linux

Linux之fork與vfork區別


Linux之fork與vfork區別


創建一個新進程的方法只有由某個已存在的進程調用fork()或vfork()



1.fork()函數




返回值:成功:父進程:返回子進程的PID
子進程:返回0
失敗:父進程返回-1
子進程是父進程的一個拷貝。即子進程從父進程得到數據段和堆、棧段的拷貝,這些需要分配新的內存(不是與父進程共享,而是單獨分配內存);而對於只讀的代碼段,通常使用共享內存的方式訪問。
fork返回後,子進程和父進程都從調用fork函數的下一條語句開始執行。
由於子進程與父進程的運行是無關的,所以,父進程可先於子進程運行,子進程也可以先於父進程運行
eg:
myfork.c



Makefile




運行結果




以前的fork創建一個子進程時,將會創建一個新的地址空間,並且拷貝父進程的資源,然後將會有兩種行為:1.執行從父進程那裡拷貝過來的代碼段(進程希望復制自身,從而父子進程能同時執行不同段的代碼);2. 調用exec執行一個新的代碼段(進程想執行另外一個程序)
當進程調用exec時,一個進程替換了當前進程的文本、數據、棧、堆段。這樣,前面的拷貝工作就白費力氣了,這種情況下,人們想出了vfork。
vfork並不復制父進程的進程環境,子進程在父進程的地址空間中運行,所以子進程不能進行寫操作,並且兒子“霸占”著父親的房子的時候,就要委屈父親一下,讓他在外面歇著(阻塞),一旦兒子執行了exec或者exit後,相當於兒子買了屬於自己的房子,這時候就相當於分家了
2.vfork()函數




vfork創建新進程的主要目的在於調用exec函數執行另外的一個新程序,在沒調用exec或exit之前,子進程的運行是與父進程共享數據段的。
vfork調用中,子進程先運行,父進程掛起,直到子進程調用exec或者exit,在這以後,父子進程的執行順序不再被限制。
eg:
myvfork.c



Makefile




運行結果




一個經典的例子
test.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <unistd.h>
  5. void test()
  6. {
  7. pid_t pid;
  8. pid=vfork();
  9. if(pid<0) //失敗
  10. {
  11. printf("vfork error\n");
  12. exit(0);
  13. }
  14. else if(pid==0)
  15. {
  16. printf("1:child pid=%d,ppid=%d\n",getpid(),getppid());
  17. return; //return執行完後,把控制權交給調用函數,而exit()執行完後把控制權交給系統 ,改成_exit(0),則會有另一種結果
  18. }
  19. else
  20. {
  21. printf("2:parent pid=%d,ppid=%d\n",getpid(),getppid());
  22. }
  23. }
  24. void fun()
  25. {
  26. int i=0;
  27. int buf[100];
  28. for(;i<100;i++)
  29. {
  30. buf[i]=0;
  31. }
  32. printf("3:child pid=%d,ppid=%d\n",getpid(),getppid());
  33. }
  34. int main()
  35. {
  36. test();
  37. fun();
  38. return 0;
  39. }
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void test()
{
    pid_t pid;
    pid=vfork();
    if(pid<0)  //失敗
    {
        printf("vfork error\n");
        exit(0);
    }
    else if(pid==0)
    {
        printf("1:child pid=%d,ppid=%d\n",getpid(),getppid());
        return;  //return執行完後,把控制權交給調用函數,而exit()執行完後把控制權交給系統 ,改成_exit(0),則會有另一種結果
    }
    else
    {
        printf("2:parent pid=%d,ppid=%d\n",getpid(),getppid());
    }
}
void fun()
{
    int i=0;
    int buf[100];
    for(;i<100;i++)
    {
        buf[i]=0;
    }
    printf("3:child pid=%d,ppid=%d\n",getpid(),getppid());
}
int main()
{
    test();
    fun();
    return 0;
}

Makefile



運行結果




程序在後續執行時出現了錯誤,並且可知道是在父進程中出現的錯誤
vfork函數調用時,子進程比父進程先運行,在調用test()函數執行時,子進程執行完之後,將清理test函數的棧空間,然後子進程再調用fun()函數,將覆蓋掉test的棧空間,繼續執行fun函數。但是,當子進程退出後,執行父進程,但是,在test函數返回的時候該棧空間已經被子進程破壞了,不存在了,所以就出現了棧錯誤
區別:
1.vfork保證子進程先運行,在它調用exec或者exit之後,父進程才可能被調度運行,之後,父子進程的執行順序才不再有限制。如果在調用exec或者exit之前,子進程依賴於父進程的進一步動作,則會導致死鎖
2.fork要拷貝父進程的進程環境(數據段),而vfork不需要完全拷貝父進程的進程環境(數據段),在調用exec或者exit之前,父子進程共享進程環境(數據段),相當於線程概念,此時父進程阻塞等待(因為子進程先運行)。
結束子進程:
exit和_exit函數用於正常終止一個程序,_exit()立即進入內核,exit()則需要先執行一些清除處理(包括調用執行各終止處理程序,關閉所有標准I/O流等),然後再進入內核。
結束子進程不用exit(0),而使用_exit(0)。因為_exit(0)在結束進程時,不對標准I/O流進行任何操作,而exit(0)回關閉進程的所有標准I/O流

http://xxxxxx/Linuxjc/1145151.html TechArticle

Copyright © Linux教程網 All Rights Reserved