歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linuxfork與vfork的深入分析(一)

Linuxfork與vfork的深入分析(一)

日期:2017/2/25 10:38:42   编辑:Linux教程
 一)fork的概述

  .操作系統對進程的管理,是通過進程表完成的.進程表中的每一個表項,記錄的是當前操作系統中一個進程的信息.

  .進程在系統的唯一標識是PID,PID是一個從1到32768的正整數,其中1一般是特殊進程init,其它進程從2開始依次編號.當用完32768後,從2重新開始.

  .一個稱為“程序計數器(program counter, pc)”的寄存器,指出當前占用 CPU的進程要執行的下一條指令的位置

  .當分給某個進程的 CPU時間已經用完,操作系統將該進程相關的寄存器的值,保存到該進程在進程表中對應的表項裡面,把將要接替這個進程占用 CPU的那個進程的上下文,從進程表中讀出,並更新相應的寄存器.

  二)fork的一個例子:

  #include <sys/types.h>

  #include <sys/types.h>

  #include <unistd.h>

  #include <stdio.h>

  int main()

  {

  pid_t pid;

  pid=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());

  }

  gcc test1.c -o test1

  debian:/tmp# ./test1

  I am the child process,ID is 2723

  I am the parent process,ID is 2722

  程序分析:

  1)pid=fork();

  先來看看子進程的表現:

  操作系統調用fork()函數創建一個新的進程(子進程),並且在進程表中相應為它建立一個新的表項,

  此時子進程得到CPU的調度,它的上下文被換入,占據 CPU,操作系統對fork的實現,使得子進程中fork調用返回0

  所以在這個進程中pid=0,這個進程繼續執行的過程中,if語句中 pid<0不滿足,但是pid= =0是true。所以輸出i am the child process...

  父進程的表現:

  操作系統對fork的實現,使這個調用在父進程中返回剛剛創建的子進程的pid(一個正整數),所以下面的if語句中pid<0,

  pid==0的兩個分支都不會執行。所以輸出i am the parent process...

  2)對子進程來說,fork返回給它0,但它的pid絕對不會是0,之所以fork返回0給它,是因為它隨時可以調用getpid()來獲取自己的pid

  3)fork之後父子進程除非采用了同步手段,否則不能確定誰先運行,也不能確定誰先結束.認為子進程結束後父進程才從fork返回的,這是不對的,fork不是這樣的,vfork才這樣。

  4)父進程執行了所有的進程,而子進程只執行了fork()後面的程序,這是因為子進程繼承了父進程的PC(程序計數器).

  三)fork的另一個例子:

  #include <stdio.h>

  #include <sys/types.h>

  #include <unistd.h>

  int main()

  {

  pid_t pid1;

  pid_t pid2;

  pid1 = fork();

  pid2 = fork();

  printf("pid1:%d, pid2:%d\n", pid1, pid2);

  }

  gcc test2.c -o test2

  ./test2

  pid1:18938, pid2:0

  pid1:0, pid2:0

  pid1:18938, pid2:18939

  pid1:0, pid2:18940

  程序分析:

  1)執行test2時,啟動一個進程,設這個進程為P0,PID為xxxxx

  2)當執行到pid1 = fork();時,P0啟動了一個進程,設這個進程為P1,它的PID為18938,暫且不管P1.

  3)P0中的fork返回18938給pid1,繼續執行到pid2 = fork();此時啟動另一個新的進程,設為P2,P2的PID為18939 ,同樣暫且不管P2.

  4)P0的第二個fork返回18939給p2,最後P0的執行結果為pid1:18938, pid2:18939

  5)再看P2,P2生成時,P0中的pid1=18938,所以P2中的pid1繼承P0的pid1=18938,而作為子進程pid2=0,P2從第二個fork後開始執行,

  最後輸出pid1:18938, pid2:0.

  6)回頭看P1,P1中第一條fork返回0給pid1,然後接著執行後面的語句.而後面接著的語句是pid2 = fork();執行到這裡,P1又產生了一個新進程,設為P3,先不管P3.

  7)P1中第二條fork將P3的PID返回給pid2,P3的PID為18940,所以P1的pid2=18940。P1繼續執行後續程序,結束,輸出“pid1:0, pid2:18940”.

  8)P3作為P1的子進程,繼承P1中pid1=0,並且第二條fork將0返回給pid2,所以P3最後輸出“pid1:0, pid2:0”.

  9)所有的進程都執行完畢.

  四)vfork與fork的區別

  vfork與fork主要有三點區別:

  .fork():子進程拷貝父進程的數據段,堆棧段

  vfork():子進程與父進程共享數據段

  .fork()父子進程的執行次序不確定vfork 保證子進程先運行,在調用 exec 或 exit 之前與父進程數據是共享的,在它調用 exec或 exit 之後父進程才可能被調度運行。

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

  1)先用fork()進行試驗

  #include <unistd.h>

  #include <stdio.h>

  int main(void)

  {

  pid_t pid;

  int count=0;

  pid=fork();

  count++;

  printf("count= %d\n",count);

  return 0;

  }

Copyright © Linux教程網 All Rights Reserved