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個分支。