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回車符號,為何成果會相差這麼年夜呢?
#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個分支。