PHP - pcntl_fork() 執行過程詳解

 


<?php   
$pid = pcntl_fork();
if ($pid == -1)
{
    die("could not fork");
}
elseif($pid == 0)
{
    echo "I'm the child  
process  \n";
}
else
{
    echo "I'm the parent 
process  \n";
    exit;
}


要搞清楚fork的執行過程,就必須先弄清楚操做系統中」進程(process)」概念。php

一個進程,主要包含三個元素:算法

1. 一個能夠執行的程序;
2. 和該進程相關聯的所有數據(包括變量,內存空間,緩衝區等等);
3. 程序的執行上下文(execution context);
函數


不妨簡單理解爲,一個進程表示的就是一個可執行程序的一次執行過程當中的一個狀態。操做系統對進程的管理,典型的狀況,是經過進程表完成的。進程表中的每個表項,記錄的是當前操做系統中一個進程的狀況。對於單 CPU的狀況而言,每一特定時刻只有一個進程佔用 CPU,可是系統中可能同時存在多個活動的(等待執行或繼續執行的)進程。spa

一個稱爲」程序計數器(program counter, pc)」的寄存器,指出當前佔用 CPU的進程要執行的下一條指令的位置。操作系統

當分給某個進程的 CPU時間已經用完,操做系統將該進程相關的寄存器的值,保存到該進程在進程表中對應的表項裏面;把將要接替這個進程佔用 CPU的那個進程的上下文,從進程表中讀出,並更新相應的寄存器(這個過程稱爲」上下文交換(process context switch)」,實際的上下文交換須要涉及到更多的數據,那和fork無關,再也不多說,主要要記住程序寄存器pc指出程序當前已經執行到哪裏,是進程上 下文的重要內容,換出 CPU的進程要保存這個寄存器的值,換入CPU的進程,也要根據進程表中保存的本進程執行上下文信息,更新這個寄存器)。指針

好了,有這些概念打底,能夠說fork了,當你的程序執行到下面的語句:
pid = pcntl_fork();
操做系統建立一個新的進程(子進程),而且在進程表中相應爲它創建一個新的表項。新進程和原有進程的可執行程序是同一個程序;上下文和數據,絕大部分就是原進程(父進程)的拷貝,但它們是兩個相互獨立的進程!此時程序寄存器pc在父、子進程的上下文中都聲稱,這個進程目前執行到fork調用即將返回(此時子進程不佔有CPU,子進程的pc不是真正保存在寄存器中,而是做爲進程上下文保存在進程表中的對應表項內)。問題是怎麼返回,在父子進程中就分道揚鑣。
blog

父進程繼續執行操做系統對fork的實現,使這個調用在父進程中返回剛剛建立的子進程的pid(一個正整數),因此後面的if語句中pid<0, pid==0的兩個分支都不會執行。因此輸出:i am the parent process…繼承

接着子進程在以後的某個時候獲得調度,它的上下文被換入,佔據 CPU,操做系統對fork的實現使得子進程中fork調用返回0,因此在這個進程中pid=0(注意這不是父進程了哦,雖然是同一個程序,可是這是同一個程序的另一次執行,在操做系統中此次執行是由另一個進程表示的,從執行的角度說和父進程相互獨立)。這個進程在繼續執行的過程當中,if語句中 pid<0不知足,可是pid==0是true,因此輸出:i am the child process…進程

我想你比較困惑的就是:內存

爲何看上去程序中互斥的兩個分支都被執行了,在一個程序的一次執行中,這固然是不可能的,事實上你看到的兩行輸出是來自兩個獨立的進程,而這兩個進程來自同一個程序的兩次執行。

-----------------------------------------

fork以後,操做系統會複製一個與父進程徹底相同的子進程,雖然說是父子關係,可是在操做系統看來,他們更像兄弟關係,這2個進程共享代碼空間,可是數據空間是互相獨立的,子進程數據空間中的內容是父進程的完整拷貝,指令指針也徹底相同,但只有一點不一樣,若是fork成功,子進程中fork的返回值是0,父進程中fork的返回值是子進程的進程號,若是fork失敗,父進程會返回錯誤。
能夠這樣想象,2個進程一直同時運行,並且步調一致,在fork以後,他們分別做不一樣的工做,也就是分岔了,這也是fork爲何叫fork的緣由。
至於哪個進程最早運行,這與操做系統平臺的調度算法有關,並且這個問題在實際應用中並不重要,若是須要父子進程協同運做,能夠經過控制語法結構的辦法解決。

-----------------------------------------

fork前子進程能夠繼承父進程的東西,可是在pcntl_fork()後子進程和父進程就沒有任何繼承關係了。在子進程裏建立的東西是子進程的,在父進程建立的東西是父進程的,能夠徹底當作是兩個獨立的進程。

-----------------------------------------

在程序段裏用了pcntl_fork()以後程序出了分岔,派生出了兩個進程,具體哪一個先運行就看該系統的調度算法了。
在這裏,咱們能夠這麼認爲,在運行到」pid=pcntl_fork();」時系統派生出一個跟主程序如出一轍的子進程。該進程的」pid=pcntl_fork();」一句中 pid獲得的就是子進程自己的pid;子進程結束後,父進程的」pid=pcntl_fork();」中pid獲得的就是父進程自己的pid,所以該程序有兩行輸出。

-----------------------------------------

pcntl_fork()函數複製了當前進程的PCB,並向父進程返回了派生子進程的pid,父子進程並行,打印語句的前後徹底看系統的調度算法,打印的內容控制則靠pid變量來控制。由於咱們知道pcntl_fork()向父進程返回了派生子進程的pid,是個正整數;而派生子進程的pid變量並無被改變,這一區別使得咱們看到了他們的不一樣輸出。

-----------------------------------------

1. 派生子進程的進程,即父進程,其pid不變;
2. 對子進程來講,fork()函數返回給它0, 但它自身的pid絕對不會是0;之因此fork()函數返回0給它,是由於它隨時能夠調用getpid()來獲取本身的pid;
3. fork以後父、子進程除非採用了同步手段,不然不能肯定誰先運行,也不能肯定誰先結束。認爲子進程結束後父進程才從fork返回的,這是不對的,fork不是這樣的,vfork才這樣。

-----------------------------------------

相關文章
相關標籤/搜索