fork函數的理解1


一、一個進程的構成

   一個進程由正文段(即代碼段)、用戶數據段以及系統數據段。

其中系統數據段又稱進程控制塊(PCB),是給操作系統進行調度用的。系統數據段中存放了關於這個進程的:PID 、PPID、優先級、占用的資源、該進程的狀態等等。

fork函數用於進程創建。

看下面一段代碼

   1:  #include <stdio.h>
   2:  #include <unistd.h>
   3:  #include <stdlib.h>
   4:  #include <sys/types.h>
   5:   
   6:   
   7:  int main(void)
   8:  {
   9:      int a = 0;
  10:      pid_t pid;
  11:   
  12:   
  13:      if((pid = fork()) == -1)
  14:      {
  15:          printf("fork error!\n");
  16:          exit(-1);
  17:      }
  18:   
  19:      if(pid == 0)
  20:      {
  21:          a++;
  22:          printf("child result= %d, pid=%d, ppid=%d, a=%d, &a=%p\n",pid,getpid(),getppid(),a,&a);
  23:      }
  24:      else
  25:      {
  26:          printf("parent  result= %d, pid=%d, ppid=%d, a=%d, &a=%p\n",pid,getpid(),getppid(),a,&a);
  27:   
  28:      }
  29:      return 0;
  30:  }

比如此刻有一個進程P1剛開始執行該程序,但執行到fork函數,進入fork函數體內,此時程序計數器PC(PC中存放的是返回地址,當返回后會把返回值給了pid這個變量)壓棧, fork會創建一個P1的子進程P2,P2同樣也是有三部分構成(正文段(即代碼段)、用戶數據段以及系統數據段),這三段基本上與其父進程完全一樣,包括壓到棧的PC,不同的是他們的pid以及ppid。P2的ppid是P1的進程號,而P1的ppid就是shell的進程號。可以這么理解,此時在內存中有如下兩個同樣的部分。

                   父PS1的                                                                                 子PS2的

image

image

                     

執行  pstree  命令后

 

image

他們的家族關系是:

image

可以看到,P1的父進程是bash。

 

所以當執行完fork函數后,P1和P2都返回,PC出棧,但是P2並不再執行fork函數和fork函數前面的程序,而是將fork的返回值賦值給變量pid。

看一下輸出:

image

 

二、注意

  • 當子進程先於父進程結束,子進程的狀態變為 Z,又稱“僵屍態”,即雖然結束了,但是還占有一些資源。子進程的資源回收由其父進程負責。
  • 當父進程先於子進程結束,子進程有init進程負責回收。但是此時子進程不在受shell控制,變為后台進程,假如子進程中有getchar等需要用戶輸入,getchar會返回-1。

當出現第二種情況時,gnome-terminal輸出會有點亂:

image

 

  • 從輸出可以看出,兩次輸出的a的地址相同,原因:

image

即: 子進程和父進程中的a的虛擬地址相同,但是物理地址不同。其中內存管理單元MMU完成虛擬內存和物理內存的轉換。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: