這兩天在看linux的fork函數,把這兩天看到的消化一下,說說個人理解。html
主要得益與兩篇大牛的文章:linux
推薦先看這篇:從一道面試題談linux下的fork運行機制面試
再看這篇:Linux中fork()函數詳解
算法
第一篇雖然只有一個例子,可是感受把fork的執行過程介紹很詳盡,第二篇的例子很經典,可是對剛學的小白來講有點困難。函數
接下來談談看過以後個人總結與理解
操作系統
首先必須明確一下幾點:
code
1.進程在linux中成樹狀結構, init爲根節點,其它進程均有父進程,某進程的父進程就是啓動這個進程的進程,這個進程叫作父進程的子進程。htm
2.fork函數的做用就是建立一個子進程,子進程複製父進程的代碼段,數據段,BSS段,堆,棧等全部用戶空間的信息,在內核中操做系統爲其從新申請了一個PCB,而且使用父進程的PCB來初始化,除了PID等特殊信息外,幾乎全部的信息都是同樣的
blog
3.父子進程在建立了子進程後互相不關聯,以獨立身份搶佔CPU資源,具體誰先執行有調度算法決定,用戶空間沒有辦法干預,繼承
4.子進程開始執行代碼的位置是fork函數執行後的代碼處,以前的都是繼承父進程的
下面結合兩個例子闡述一下fork的執行
例1:
#include <stdio.h> #include <unistd.h> int main(){ int count = 0; pid_t = fork(); if(pid < 0) printf("error in fork!\n"); else if(pid == 0){ count++; printf("child: count = %d\n",count); else{ count++; printf("father: count = %d\n",count); } return 0; }
結果:
father :count = 1
child:count = 1
在fork以後,父進程就建立了一個新的進程(子進程),子進程基本上就是父進程的副本,父進程中count=0,子進程就從父進程中繼承該值,兩個進程都執行if {....}. else if {.....} else{ ...}條件判斷語句,只不過在執行了fork以後,父子進程中pid的值是不同的的,父進程中pid是子進程的進程號,子進程的pid是0,因此兩進程進入的就是不一樣的條件判斷子句,可是兩進程之間的count之間是互補影響的,因此打印的都是1
因此對於條件判斷語句兩個進程執行的是不一樣的,
#include <stdio.h> #include <unistd.h> int main(){ fork();//step1 fork();//step2 return 0; }
上述程序產生了多少個進程。
step1:最初的進程假設爲p0,fork函數產生一個子進程p1,以後p1繼承p0的代碼段,數據段,BSS段等信息,從step處開始執行,p0也接着執行。
step2:p0產生子進程p2,p1產生子進程p3,因此最後共p0,p1,p2,p3四個進程。
#include <stdio.h> #include <unistd.h> int main(){ pid_t pid; printf("fork \n");//*** //printf("fork");//*** pid = fork(); if(pid < 0) printf("error in fork!\n"); else if(pid == 0){ printf("child\n"); else{ printf("father\n"); }
***的兩個printf
選擇帶\n的結果:
fork
child
father
選擇不帶\n的結果:
fork child
fork father
爲何一個換行符就能有這麼大差異:
這與printf的緩衝機制有關,printf某些內容時,操做系統僅僅是把該內容放到了stdout的緩衝隊列並無實際的寫到屏幕,可是隻要看到\n就會打印並刷新stdout,上述程序選擇執行帶\n的printf的話,子進程沒法從父進程中繼承fork,而若是選咋執行不帶\n的printf的話,子進程繼承父進程的流緩衝區,等到執行printf("child\n");時遇到\n時同時輸出fork child。
若是想煉手能夠看文章開頭的第二篇文章,原理就是這些,接下來的就是推敲畫圖分析了。