<ruby id="l3bz1"><th id="l3bz1"></th></ruby>

    <font id="l3bz1"><p id="l3bz1"></p></font>

    <ol id="l3bz1"><th id="l3bz1"><p id="l3bz1"></p></th></ol>

    <menuitem id="l3bz1"><th id="l3bz1"><var id="l3bz1"></var></th></menuitem>
    <menuitem id="l3bz1"></menuitem>

          <ol id="l3bz1"></ol>
          <menuitem id="l3bz1"><th id="l3bz1"><var id="l3bz1"></var></th></menuitem>

          <menuitem id="l3bz1"></menuitem>

          新聞動態

          淺談Linux vfork與fork簡單對比分析

          發布日期:2022-04-22 12:43 | 文章來源:源碼中國

          本文分享了Linux vfork與fork簡單對比分析,分享給大家,具體如下:

          fork相關問題:

          一、fork基礎了解

          fork作用為創建一個子進程,在使用了fork命令后,內核會分配新的內存塊和數據結構給子進程,并且將父進程的部分數據結構內容拷貝到子進程,最后再將子進程添加到系統進程列表中,添加完成后fork返回,開始調度。

          頭文件:#include < unistd.h >

          函數原型:pid_t fork( )

          返回值:返回值大于0則當前進程為父進程,等于0代表為子進程,小于零代表創建子進程失敗。

          通過一個例子來了解:

            #include <stdio.h>
            #include <unistd.h>
            
              
            int main()
            {
              int tmp = 5;
              pid_t res = fork();
              if(res < 0){
               //fork失敗
               perror("fork");
             }else if(res == 0){
               //該進程為子進程
               printf("im child[%d],fasther is %d,tmp is %d.\n",getpid(),getppid(),tmp++);
             }else{
               //該進程為父進程
               printf("im father[%d],tmp is %d.\n",getpid(),tmp++);
             }
             printf("tmp = %d\n",tmp);
             return 0;
           }     

          運行結果:

          im father[3128],tmp is 5.
          tmp = 6
          im child[3129],fasther is 1,tmp is 5.
          tmp = 6

          相關問題小結:

          通過結果很明顯的能看出本次調用中,先執行父進程,對應pid為3128,在父進程中tmp++,所以輸出為6;關鍵問題在于子進程,有兩個關鍵點。

          ①為什么結果中子進程父親pid為1:通過輸出我們能看出父進程先執行完成后才執行的子進程,也就是說當子進程執行時父進程已結束,此時該子進程相當于一個孤兒進程,被pid為1也就是Init進程所管理,所以子進程的ppid為1;

          ②為什么子進程最后輸出tmp值還為6: fork進程采用的是寫時拷貝,父子進程一開始共享一片內存區域,但是只有有一方要對數據進行修改,則再開辟一塊空間,防止相互修改影響。所以在上述代碼中,雖說是一個tmp,其實內存中各自保留了一份值。

          二、關于fork過程中寫時拷貝:


          這下就不難看出,父子進程數據段和代碼段開始時是共享一塊對應的內存,當一方嘗試寫入時,便產生了寫時拷貝。需要注意的是:fork之前,父進程獨立執行,fork之后,父子兩個執行流分別執行,至于誰先執行,由調度器決定??赏ㄟ^下面例子很明顯的看出是從fork之后才分別執行。

            #include <stdio.h>
            #include <unistd.h>
            
            
            int main()
            {
              int tmp = 5;
              printf("There is fork before\n");
              pid_t res = fork();
             if(res < 0){
               //fork失敗
               perror("fork");
             }else if(res == 0){
               //該進程為子進程
               printf("im child[%d],tmp is %d.\n",getpid(),tmp++);
             }else{
               //該進程為父進程
               printf("im father[%d],tmp is %d.\n",getpid(),tmp++);
             }
             printf("tmp = %d\n",tmp);
             return 0;
           }
          

          輸出結果:

          There is fork before

          im father[3625],tmp is 5.

          tmp = 6

          im child[3626],tmp is 5.

          tmp = 6

          三、fork調用失敗的原因:

          ①系統中已經存在太多進程,無法再創建新的進程??赏ㄟ^ulimit -a命令查看當前所有的資源限制。

          ②內存不足,由于開辟每個新的進程都要分配一個PCB,并為新進程分配資源,內存都不足也就別提還想著再創建進程了。

          vfork相關問題:

          一、vfork基礎了解

          <1>vfork創建新進程的主要目的在于用exec函數執行另外的程序,實際上,在沒調用exec或_exit之前子進程與父進程共享數據段。在vfork調用中,子進程先運行,父進程掛起,直到子進程調用exec或_exit,在這以后,父子進程的執行順序不再有限制。

          頭文件:#include < unistd.h >

          函數原型:pid_t vfork( )

          返回值:返回值大于0則當前進程為父進程,等于0代表為子進程,小于零代表創建子進程失敗。

          通過一個例子來了解:

           #include <stdio.h>
            #include <unistd.h>
            
            int tmp = 3;
            
            int main()
            {
              pid_t res = vfork();
              if(res < 0){
               perror("vfork");
               _exit();
             }else if(res == 0){
              tmp = 10;
           printf("child res = %d\n",tmp);
               _exit(0);
             }else{
               printf("father res = %d\n",tmp);
             }
           
             return 0;
           }
          

          輸出結果:

          child res = 10

          father res = 10

          結果分析:正如上面所說的,子進程直接公用父進程的頁表,改變子進程的數據也會影響到父進程。

          <2>vfork用處:

          vfork()跟fork()類似,都是創建一個子進程,這兩個函數的的返回值也具有相同的含義。但是vfork()創建的子進程基本上只能做一件事,那就是立即調用_exit()函數或者exec函數族成員,調用任何其它函數(包括exit())、修改任何數據(除了保存vfork()返回值的那個變量)、執行任何其它語句(包括return)都是不應該的。更需要注意的是:調用vfork()之后,父進程會一直阻塞,直到子進程調用_exit()終止,或者調用exec函數族成員。

          <3>為什么只能用_exit退出:

          exit()是對_exit()的封裝,它自己在調用_exit()前會做很多清理工作,其中包括刷新并關閉當前進程使用的流緩沖(比如stdio.h里面的printf等),由于vfork()的子進程完全共享了父進程地址空間,子進程里面的流也是共享的父進程的流,所以子進程里面是不能做這些事的。直接return就更不行了,子進程return以后,會從當前函數的外部調用點后面繼續執行,這后面子進程可能將會執行很多語句,結果就沒法預料了。在man手冊中也強調了這一點,必須使用_exit退出。

          fork與vfork的區別

          1.vfork保證子進程先運行,在它調用exec或exit之后父進程才可能被調度運行。如果在調用這兩個函數之前子進程依賴于父進程的進一步動作,則會導致死鎖。

          2.fork要拷貝父進程的進程環境;而vfork則不需要完全拷貝父進程的進程環境,在子進程沒有調用exec和exit之前,子進程與父進程共享進程環境,相當于線程的概念,此時父進程阻塞等待。

          為什么會有vfork呢?

          因為以前的fork當它創建一個子進程時,將會創建一個新的地址空間,并且拷貝父進程的資源,然后將會有兩種行為:

          1.執行從父進程那里拷貝過來的代碼段

          2.調用一個exec執行一個新的代碼段

          當進程調用exec函數時,一個新程序替換了當前進程的正文,數據,堆和棧段。這樣,前面的拷貝工作就是白費力氣了,這種情況下,聰明的人就想出了vfork。vfork并不復制父進程的進程環境,子進程在父進程的地址空間中運行,所以子進程不能進行寫操作,并且在兒子“霸占”著老子的房子時候,要委屈老子一下了,讓他在外面歇著(阻塞),一旦兒子執行了exec或者exit后,相當于兒子買了自己的房子了,這時候就相當于分家了。

          因此,如果創建子進程是為了調用exec執行一個新的程序的時候,就應該使用vfork

          以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

          版權聲明:本站文章來源標注為YINGSOO的內容版權均為本站所有,歡迎引用、轉載,請保持原文完整并注明來源及原文鏈接。禁止復制或仿造本網站,禁止在非www.ddmudiao.com所屬的服務器上建立鏡像,否則將依法追究法律責任。本站部分內容來源于網友推薦、互聯網收集整理而來,僅供學習參考,不代表本站立場,如有內容涉嫌侵權,請聯系alex-e#qq.com處理。

          相關文章

          實時開通

          自選配置、實時開通

          免備案

          全球線路精選!

          全天候客戶服務

          7x24全年不間斷在線

          專屬顧問服務

          1對1客戶咨詢顧問

          在線
          客服

          在線客服:7*24小時在線

          客服
          熱線

          400-630-3752
          7*24小時客服服務熱線

          關注
          微信

          關注官方微信
          頂部