PHP - pcntl_fork() 執(zhí)行過(guò)程詳解

<?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的執(zhí)行過(guò)程楷掉,就必須先弄清楚操作系統(tǒng)中”進(jìn)程(process)”的概念吵瞻。

一個(gè)進(jìn)程运嗜,主要包含三個(gè)元素:
1. 一個(gè)可以執(zhí)行的程序仲翎;
2. 和該進(jìn)程相關(guān)聯(lián)的全部數(shù)據(jù)(包括變量痹扇,內(nèi)存空間,緩沖區(qū)等等)溯香;
3. 程序的執(zhí)行上下文(execution context)鲫构;


不妨簡(jiǎn)單理解為,一個(gè)進(jìn)程表示的就是一個(gè)可執(zhí)行程序的一次執(zhí)行過(guò)程中的一個(gè)狀態(tài)玫坛。操作系統(tǒng)對(duì)進(jìn)程的管理结笨,典型的情況,是通過(guò)進(jìn)程表完成的。進(jìn)程表中的每一個(gè)表項(xiàng)炕吸,記錄的是當(dāng)前操作系統(tǒng)中一個(gè)進(jìn)程的情況伐憾。對(duì)于單 CPU的情況而言,每一特定時(shí)刻只有一個(gè)進(jìn)程占用 CPU赫模,但是系統(tǒng)中可能同時(shí)存在多個(gè)活動(dòng)的(等待執(zhí)行或繼續(xù)執(zhí)行的)進(jìn)程树肃。

一個(gè)稱為”程序計(jì)數(shù)器(program counter, pc)”的寄存器,指出當(dāng)前占用 CPU的進(jìn)程要執(zhí)行的下一條指令的位置瀑罗。

當(dāng)分給某個(gè)進(jìn)程的 CPU時(shí)間已經(jīng)用完扫外,操作系統(tǒng)將該進(jìn)程相關(guān)的寄存器的值,保存到該進(jìn)程在進(jìn)程表中對(duì)應(yīng)的表項(xiàng)里面廓脆;把將要接替這個(gè)進(jìn)程占用 CPU的那個(gè)進(jìn)程的上下文筛谚,從進(jìn)程表中讀出,并更新相應(yīng)的寄存器(這個(gè)過(guò)程稱為”上下文交換(process context switch)”停忿,實(shí)際的上下文交換需要涉及到更多的數(shù)據(jù)驾讲,那和fork無(wú)關(guān),不再多說(shuō)席赂,主要要記住程序寄存器pc指出程序當(dāng)前已經(jīng)執(zhí)行到哪里吮铭,是進(jìn)程上 下文的重要內(nèi)容,換出 CPU的進(jìn)程要保存這個(gè)寄存器的值颅停,換入CPU的進(jìn)程谓晌,也要根據(jù)進(jìn)程表中保存的本進(jìn)程執(zhí)行上下文信息,更新這個(gè)寄存器)癞揉。

好了纸肉,有這些概念打底,可以說(shuō)fork了喊熟,當(dāng)你的程序執(zhí)行到下面的語(yǔ)句:
pid = pcntl_fork();
操作系統(tǒng)創(chuàng)建一個(gè)新的進(jìn)程(子進(jìn)程)柏肪,并且在進(jìn)程表中相應(yīng)為它建立一個(gè)新的表項(xiàng)。新進(jìn)程和原有進(jìn)程的可執(zhí)行程序是同一個(gè)程序芥牌;上下文和數(shù)據(jù)烦味,絕大部分就是原進(jìn)程(父進(jìn)程)的拷貝,但它們是兩個(gè)相互獨(dú)立的進(jìn)程壁拉!此時(shí)程序寄存器pc在父谬俄、子進(jìn)程的上下文中都聲稱,這個(gè)進(jìn)程目前執(zhí)行到fork調(diào)用即將返回(此時(shí)子進(jìn)程不占有CPU弃理,子進(jìn)程的pc不是真正保存在寄存器中溃论,而是作為進(jìn)程上下文保存在進(jìn)程表中的對(duì)應(yīng)表項(xiàng)內(nèi))。問(wèn)題是怎么返回案铺,在父子進(jìn)程中就分道揚(yáng)鑣蔬芥。

父進(jìn)程繼續(xù)執(zhí)行操作系統(tǒng)對(duì)fork的實(shí)現(xiàn)梆靖,使這個(gè)調(diào)用在父進(jìn)程中返回剛剛創(chuàng)建的子進(jìn)程的pid(一個(gè)正整數(shù))控汉,所以后面的if語(yǔ)句中pid<0, pid==0的兩個(gè)分支都不會(huì)執(zhí)行笔诵。所以輸出:i am the parent process…

接著子進(jìn)程在之后的某個(gè)時(shí)候得到調(diào)度,它的上下文被換入姑子,占據(jù) CPU乎婿,操作系統(tǒng)對(duì)fork的實(shí)現(xiàn)使得子進(jìn)程中fork調(diào)用返回0,所以在這個(gè)進(jìn)程中pid=0(注意這不是父進(jìn)程了哦街佑,雖然是同一個(gè)程序谢翎,但是這是同一個(gè)程序的另外一次執(zhí)行,在操作系統(tǒng)中這次執(zhí)行是由另外一個(gè)進(jìn)程表示的沐旨,從執(zhí)行的角度說(shuō)和父進(jìn)程相互獨(dú)立)森逮。這個(gè)進(jìn)程在繼續(xù)執(zhí)行的過(guò)程中,if語(yǔ)句中 pid<0不滿足磁携,但是pid==0是true褒侧,所以輸出:i am the child process…

我想你比較困惑的就是:

為什么看上去程序中互斥的兩個(gè)分支都被執(zhí)行了,在一個(gè)程序的一次執(zhí)行中谊迄,這當(dāng)然是不可能的闷供,事實(shí)上你看到的兩行輸出是來(lái)自兩個(gè)獨(dú)立的進(jìn)程,而這兩個(gè)進(jìn)程來(lái)自同一個(gè)程序的兩次執(zhí)行统诺。

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

fork之后歪脏,操作系統(tǒng)會(huì)復(fù)制一個(gè)與父進(jìn)程完全相同的子進(jìn)程,雖說(shuō)是父子關(guān)系粮呢,但是在操作系統(tǒng)看來(lái)婿失,他們更像兄弟關(guān)系,這2個(gè)進(jìn)程共享代碼空間啄寡,但是數(shù)據(jù)空間是互相獨(dú)立的移怯,子進(jìn)程數(shù)據(jù)空間中的內(nèi)容是父進(jìn)程的完整拷貝,指令指針也完全相同这难,但只有一點(diǎn)不同舟误,如果fork成功,子進(jìn)程中fork的返回值是0姻乓,父進(jìn)程中fork的返回值是子進(jìn)程的進(jìn)程號(hào)嵌溢,如果fork失敗,父進(jìn)程會(huì)返回錯(cuò)誤蹋岩。
可以這樣想象赖草,2個(gè)進(jìn)程一直同時(shí)運(yùn)行,而且步調(diào)一致剪个,在fork之后秧骑,他們分別作不同的工作,也就是分岔了,這也是fork為什么叫fork的原因乎折。
至于哪一個(gè)進(jìn)程最先運(yùn)行绒疗,這與操作系統(tǒng)平臺(tái)的調(diào)度算法有關(guān),而且這個(gè)問(wèn)題在實(shí)際應(yīng)用中并不重要骂澄,如果需要父子進(jìn)程協(xié)同運(yùn)作吓蘑,可以通過(guò)控制語(yǔ)法結(jié)構(gòu)的辦法解決。

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

fork前子進(jìn)程可以繼承父進(jìn)程的東西坟冲,但是在pcntl_fork()后子進(jìn)程和父進(jìn)程就沒(méi)有任何繼承關(guān)系了磨镶。在子進(jìn)程里創(chuàng)建的東西是子進(jìn)程的,在父進(jìn)程創(chuàng)建的東西是父進(jìn)程的健提,可以完全看成是兩個(gè)獨(dú)立的進(jìn)程琳猫。

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

在程序段里用了pcntl_fork()之后程序出了分岔,派生出了兩個(gè)進(jìn)程私痹,具體哪個(gè)先運(yùn)行就看該系統(tǒng)的調(diào)度算法了脐嫂。
在這里,我們可以這么認(rèn)為侄榴,在運(yùn)行到”pid=pcntl_fork();”時(shí)系統(tǒng)派生出一個(gè)跟主程序一模一樣的子進(jìn)程雹锣。該進(jìn)程的”pid=pcntl_fork();”一句中 pid得到的就是子進(jìn)程本身的pid;子進(jìn)程結(jié)束后癞蚕,父進(jìn)程的”pid=pcntl_fork();”中pid得到的就是父進(jìn)程本身的pid蕊爵,因此該程序有兩行輸出。

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

pcntl_fork()函數(shù)復(fù)制了當(dāng)前進(jìn)程的PCB桦山,并向父進(jìn)程返回了派生子進(jìn)程的pid攒射,父子進(jìn)程并行,打印語(yǔ)句的先后完全看系統(tǒng)的調(diào)度算法恒水,打印的內(nèi)容控制則靠pid變量來(lái)控制会放。因?yàn)槲覀冎纏cntl_fork()向父進(jìn)程返回了派生子進(jìn)程的pid,是個(gè)正整數(shù)钉凌;而派生子進(jìn)程的pid變量并沒(méi)有被改變咧最,這一區(qū)別使得我們看到了他們的不同輸出。

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

1. 派生子進(jìn)程的進(jìn)程御雕,即父進(jìn)程矢沿,其pid不變;
2. 對(duì)子進(jìn)程來(lái)說(shuō)酸纲,fork()函數(shù)返回給它0, 但它自身的pid絕對(duì)不會(huì)是0捣鲸;之所以fork()函數(shù)返回0給它,是因?yàn)樗S時(shí)可以調(diào)用getpid()來(lái)獲取自己的pid闽坡;
3. fork之后父栽惶、子進(jìn)程除非采用了同步手段愁溜,否則不能確定誰(shuí)先運(yùn)行,也不能確定誰(shuí)先結(jié)束外厂。認(rèn)為子進(jìn)程結(jié)束后父進(jìn)程才從fork返回的冕象,這是不對(duì)的,fork不是這樣的酣衷,vfork才這樣交惯。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末次泽,一起剝皮案震驚了整個(gè)濱河市穿仪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌意荤,老刑警劉巖啊片,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異玖像,居然都是意外死亡紫谷,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門捐寥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)笤昨,“玉大人,你說(shuō)我怎么就攤上這事握恳÷髦希” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵乡洼,是天一觀的道長(zhǎng)崇裁。 經(jīng)常有香客問(wèn)我,道長(zhǎng)束昵,這世上最難降的妖魔是什么拔稳? 我笑而不...
    開(kāi)封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮锹雏,結(jié)果婚禮上巴比,老公的妹妹穿的比我還像新娘。我一直安慰自己礁遵,他們只是感情好轻绞,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著榛丢,像睡著了一般铲球。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晰赞,一...
    開(kāi)封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天稼病,我揣著相機(jī)與錄音选侨,去河邊找鬼。 笑死然走,一個(gè)胖子當(dāng)著我的面吹牛援制,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芍瑞,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼晨仑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了拆檬?” 一聲冷哼從身側(cè)響起洪己,我...
    開(kāi)封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竟贯,沒(méi)想到半個(gè)月后答捕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屑那,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年拱镐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片持际。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沃琅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜘欲,到底是詐尸還是另有隱情益眉,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布芒填,位于F島的核電站呜叫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏殿衰。R本人自食惡果不足惜朱庆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望闷祥。 院中可真熱鬧娱颊,春花似錦、人聲如沸凯砍。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)悟衩。三九已至剧罩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間座泳,已是汗流浹背惠昔。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工幕与, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人镇防。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓啦鸣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親来氧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诫给,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容