程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> Linux中應用C說話的fork()函數創立子過程的實例教程

Linux中應用C說話的fork()函數創立子過程的實例教程

編輯:關於C++

Linux中應用C說話的fork()函數創立子過程的實例教程。本站提示廣大學習愛好者:(Linux中應用C說話的fork()函數創立子過程的實例教程)文章只能為提供參考,不一定能成為您想要的結果。以下是Linux中應用C說話的fork()函數創立子過程的實例教程正文


1、fork入門常識
一個過程,包含代碼、數據和分派給過程的資本。fork()函數經由過程體系挪用創立一個與本來過程簡直完整雷同的過程,也就是兩個過程可以做完整雷同的事,但假如初始參數或許傳入的變量分歧,兩個過程也能夠做分歧的事。
一個過程挪用fork()函數後,體系先給新的過程分派資本,例如存儲數據和代碼的空間。然後把本來的過程的一切值都復制到新的新過程中,只要多數值與本來的過程的值分歧。相當於克隆了一個本身。
 
我們來看一個例子:

#include <unistd.h> 
#include <stdio.h>  
int main ()  
{  
  pid_t fpid; //fpid表現fork函數前往的值 
  int count=0; 
  fpid=fork();  
  if (fpid < 0)  
    printf("error in fork!");  
  else if (fpid == 0) { 
    printf("i am the child process, my process id is %d/n",getpid());  
    printf("我是爹的兒子/n");//對某些人來講中文看著更直白。 
    count++; 
  } 
  else { 
    printf("i am the parent process, my process id is %d/n",getpid());  
    printf("我是孩子他爹/n"); 
    count++; 
  } 
  printf("統計成果是: %d/n",count); 
  return 0; 
} 

運轉成果是:

i am the child process, my process id is 5574
我是爹的兒子
統計成果是: 1
i am the parent process, my process id is 5573
我是孩子他爹
統計成果是: 1

在語句fpid=fork()之前,只要一個過程在履行這段代碼,但在這條語句以後,就釀成兩個過程在履行了,這兩個過程的簡直完整雷同,將要履行的下一條語句都是if(fpid<0)……
為何兩個過程的fpid分歧呢,這與fork函數的特征有關。fork挪用的一個奧妙的地方就是它僅僅被挪用一次,卻可以或許前往兩次,它能夠有三種分歧的前往值:
1)在父過程中,fork前往新創立子過程的過程ID;
2)在子過程中,fork前往0;
3)假如湧現毛病,fork前往一個負值;
 
在fork函數履行終了後,假如創立新過程勝利,則湧現兩個過程,一個是子過程,一個是父過程。在子過程中,fork函數前往0,在父過程中,fork前往新創立子過程的過程ID。我們可以經由過程fork前往的值來斷定以後過程是子過程照樣父過程。
 
援用一名網友的話來說明fpid的值為何在父子過程中分歧。“其實就相當於鏈表,過程構成了鏈表,父過程的fpid(p 意味point)指向子過程的過程id, 由於子過程沒有子過程,所以其fpid為0.
fork失足能夠有兩種緣由:
1)以後的過程數曾經到達了體系劃定的下限,這時候errno的值被設置為EAGAIN。
2)體系內存缺乏,這時候errno的值被設置為ENOMEM。
創立新過程勝利後,體系中湧現兩個根本完整雷同的過程,這兩個過程履行沒有固定的前後次序,哪一個過程先履行要看體系的過程調劑戰略。
每一個過程都有一個奇特(互不雷同)的過程標識符(process ID),可以經由過程getpid()函數取得,還有一個記載父過程pid的變量,可以經由過程getppid()函數取得變量的值。
fork履行終了後,湧現兩個過程,

有人說兩個過程的內容完整一樣啊,怎樣打印的成果紛歧樣啊,那是由於斷定前提的緣由,下面羅列的只是過程的代碼和指令,還有變量啊。
履行完fork後,過程1的變量為count=0,fpid!=0(父過程)。過程2的變量為count=0,fpid=0(子過程),這兩個過程的變量都是自力的,存在分歧的地址中,不是共用的,這點要留意。可以說,我們就是經由過程fpid來辨認和操作父子過程的。
還有人能夠困惑為何不是從#include處開端復制代碼的,這是由於fork是把過程以後的情形拷貝一份,履行fork時,過程曾經履行完了int count=0;fork只拷貝下一個要履行的代碼到新的過程。
 
2、fork進階常識
 
先看一份代碼:

#include <unistd.h> 
#include <stdio.h> 
int main(void) 
{ 
  int i=0; 
  printf("i son/pa ppid pid fpid/n"); 
  //ppid指以後過程的父過程pid 
  //pid指以後過程的pid, 
  //fpid指fork前往給以後過程的值 
  for(i=0;i<2;i++){ 
    pid_t fpid=fork(); 
    if(fpid==0) 
      printf("%d child %4d %4d %4d/n",i,getppid(),getpid(),fpid); 
    else 
      printf("%d parent %4d %4d %4d/n",i,getppid(),getpid(),fpid); 
  } 
  return 0; 
} 

運轉成果是:

  i son/pa ppid pid fpid
  0 parent 2043 3224 3225
  0 child 3224 3225  0
  1 parent 2043 3224 3226
  1 parent 3224 3225 3227
  1 child   1 3227  0
  1 child   1 3226  0 

這份代碼比擬成心思,我們來賣力剖析一下:
第一步:在父過程中,指令履行到for輪回中,i=0,接著履行fork,fork履行完後,體系中湧現兩個過程,分離是p3224和p3225(前面我都用pxxxx表現過程id為xxxx的過程)。可以看到父過程p3224的父過程是p2043,子過程p3225的父過程正好是p3224。我們用一個鏈表來表現這個關系:

p2043->p3224->p3225 

第一次fork後,p3224(父過程)的變量為i=0,fpid=3225(fork函數在父過程中返向子過程id),代碼內容為:

for(i=0;i<2;i++){ 
  pid_t fpid=fork();//履行終了,i=0,fpid=0 
  if(fpid==0) 
    printf("%d child %4d %4d %4d/n",i,getppid(),getpid(),fpid); 
  else 
    printf("%d parent %4d %4d %4d/n",i,getppid(),getpid(),fpid); 
} 
return 0; 

所以打印出成果:

  0 parent 2043 3224 3225
  0 child 3224 3225  0

第二步:假定父過程p3224先履行,當進入下一個輪回時,i=1,接著履行fork,體系中又新增一個過程p3226,關於此時的父過程,p2043->p3224(以後過程)->p3226(被創立的子過程)。
關於子過程p3225,履行完第一次輪回後,i=1,接著履行fork,體系中新增一個過程p3227,關於此過程,p3224->p3225(以後過程)->p3227(被創立的子過程)。從輸入可以看到p3225本來是p3224的子過程,如今釀成p3227的父過程。父子是絕對的,這個年夜家應當輕易懂得。只需以後過程履行了fork,該過程就釀成了父過程了,就打印出了parent。
所以打印出成果是:

  1 parent 2043 3224 3226
  1 parent 3224 3225 3227 

第三步:第二步創立了兩個過程p3226,p3227,這兩個過程履行完printf函數後就停止了,由於這兩個過程沒法進入第三次輪回,沒法fork,該履行return 0;了,其他過程也是如斯。
    以下是p3226,p3227打印出的成果:

  1 child   1 3227  0
  1 child   1 3226  0 

仔細的讀者能夠留意到p3226,p3227的父過程豈非不應是p3224和p3225嗎,怎樣會是1呢?這裡得講到過程的創立和逝世亡的進程,在p3224和p3225履行完第二個輪回後,main函數就該加入了,也即過程活該亡了,由於它曾經做完一切工作了。p3224和p3225逝世亡後,p3226,p3227就沒有父過程了,這在操作體系是不被許可的,所以p3226,p3227的父過程就被置為p1了,p1是永久不會逝世亡的,至於為何,這裡先不引見,留到“3、fork高階常識”講。
總結一下,這個法式履行的流程以下:

這個法式終究發生了3個子過程,履行過6次printf()函數。
我們再來看一份代碼:

#include <unistd.h> 
#include <stdio.h> 
int main(void) 
{ 
  int i=0; 
  for(i=0;i<3;i++){ 
    pid_t fpid=fork(); 
    if(fpid==0) 
      printf("son/n"); 
    else 
      printf("father/n"); 
  } 
  return 0; 
 
} 

它的履行成果是:

  father
  son
  father
  father
  father
  father
  son
  son
  father
  son
  son
  son
  father
  son 

    這裡就不做具體說明了,只做一個年夜概的剖析。

  for    i=0     1      2
       father   father   father
                    son
              son    father
                    son
        son    father   father
                    son
              son    father
                    son

個中每行分離代表一個過程的運轉打印成果。
總結一下紀律,關於這類N次輪回的情形,履行printf函數的次數為2*(1+2+4+……+2N)次,創立的子過程數為1+2+4+……+2N個。
網上有人說N次輪回發生2*(1+2+4+……+2N)個過程,這個說法是纰謬的,願望年夜家須要留意。
同時,年夜家假如想測一下一個法式中究竟創立了幾個子過程,最好的辦法就是挪用printf函數打印該過程的pid,也即挪用printf("%d/n",getpid());或許經由過程printf("+/n");來斷定發生了幾個過程。有人想經由過程挪用printf("+");來統計創立了幾個過程,這是不當當的。詳細緣由我來剖析。

老例子,年夜家看一下上面的代碼:
#include <unistd.h> 
#include <stdio.h> 
int main() { 
  pid_t fpid;//fpid表現fork函數前往的值 
  //printf("fork!"); 
  printf("fork!/n"); 
  fpid = fork(); 
  if (fpid < 0) 
    printf("error in fork!"); 
  else if (fpid == 0) 
    printf("I am the child process, my process id is %d/n", getpid()); 
  else 
    printf("I am the parent process, my process id is %d/n", getpid()); 
  return 0; 
} 
履行成果以下:
fork!
I am the parent process, my process id is 3361
I am the child process, my process id is 3362 
假如把語句printf("fork!/n");正文失落,履行printf("fork!");
則新的法式的履行成果是:
fork!I am the parent process, my process id is 3298
fork!I am the child process, my process id is 3299 
法式的獨一的差別就在於一個/n回車符號,為何成果會相差這麼年夜呢?
這就跟printf的緩沖機制有關了,printf某些內容時,操作體系僅僅是把該內容放到了stdout的緩沖隊列裡了,並沒有現實的寫到屏幕上。然則,只需看到有/n 則會立刻刷新stdout,是以就立時可以或許打印了。
運轉了printf("fork!")後,“fork!”僅僅被放到了緩沖裡,法式運轉到fork時緩沖外面的“fork!”  被子過程復制曩昔了。是以在子過程度stdout緩沖外面就也有了fork! 。所以,你終究看到的會是fork!  被printf了2次!!!!
而運轉printf("fork! /n")後,“fork!”被立刻打印到了屏幕上,以後fork到的子過程裡的stdout緩沖裡不會有fork! 內容。是以你看到的成果會是fork! 被printf了1次!!!!
所以說printf("+");不克不及准確地反響過程的數目。
年夜家看了這麼多能夠有點疲憊吧,不外我還得貼最初一份代碼來進一步剖析fork函數。
#include <stdio.h> 
#include <unistd.h> 
int main(int argc, char* argv[]) 
{ 
  fork(); 
  fork() && fork() || fork(); 
  fork(); 
  return 0; 
} 

 
成績是不算main這個過程本身,法式究竟創立了若干個過程。
為懂得答這個成績,我們先做一下弊,先用法式驗證一下,到此有若干個過程。
謎底是總共20個過程,除去main過程,還有19個過程。
我們再來細心剖析一下,為何是還有19個過程。
第一個fork和最初一個fork確定是會履行的。
重要在中央3個fork上,可以畫一個圖停止描寫。
這裡就須要留意&&和||運算符。
A&&B,假如A=0,就沒有需要持續履行&&B了;A非0,就須要持續履行&&B。
A||B,假如A非0,就沒有需要持續履行||B了,A=0,就須要持續履行||B。
fork()關於父過程和子過程的前往值是分歧的,依照下面的A&&B和A||B的分支停止繪圖,可以得出5個分支。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved