摘要:多進程的主進程創(chuàng)建了子進程,那主進程如何確認(rèn)子進程的狀態(tài)呢。假如主進程需要根據(jù)子進程的狀態(tài)做不同的處理呢,這里的狀態(tài)包括子進程被掉,或變成僵尸進程等。
PHP 可以通過pcntl 擴展實現(xiàn)多進程編程, 而網(wǎng)上關(guān)于如何通過pcntl 創(chuàng)建多進程的在這里就不表了, 我主要說說關(guān)于pcntl_fork的一個坑和相關(guān)的比較生僻的幾個函數(shù)的使用方式, 這也是通過挖坑和填坑得出的結(jié)論。
閑言碎語不要講, 直接開始
在實踐中, 我在使用php進行多進程實踐的模型大概如下, 期待的是每個子進程都能創(chuàng)建一個與之對應(yīng)文件, 最后父進程創(chuàng)建一個屬于父進程的文件,代碼如下(有坑):
$pid_dir = __dir__."/pid_files"; for($i=0; $i<3; $i++){ $pid = pcntl_fork(); if($pid == -1){ var_dump("fork failed"); } if(!$pid){ //子進程代碼 $pid = posix_getpid(); $ppid = posix_getppid(); $r = rand(0,100); //隨機數(shù) touch("$pid_dir/fork_child_process_{$i}_{$ppid}_{$pid}_{$r}"); } } $pid = posix_getpid(); $ppid = posix_getppid(); $r = rand(0,100); //隨機數(shù) touch("$pid_dir/fork_process_pid_{$ppid}_{$pid}_$r");
上面的代碼我通過循環(huán)創(chuàng)建3個子進程, 每個進程創(chuàng)建一個文件,完成后到最后, 父進程創(chuàng)建一個屬于他自己的文件,所以, 最后應(yīng)該會創(chuàng)建出4個文件, 但事實并非如此:
fork_child_process_0_62656_62658_39 fork_child_process_1_62656_62659_51 fork_child_process_1_62658_62660_22 fork_child_process_2_62656_62661_91 fork_child_process_2_62658_62662_22 fork_child_process_2_62659_62663_82 fork_child_process_2_62660_62664_59 fork_process_pid_62225_62656_48 fork_process_pid_62656_62658_22 fork_process_pid_62656_62659_82 fork_process_pid_62656_62661_65 fork_process_pid_62658_62660_59 fork_process_pid_62658_62662_59 fork_process_pid_62659_62663_61 fork_process_pid_62660_62664_10
為何會出現(xiàn)上面的結(jié)果, 這是因為在fork之后, 原有的進程會分裂為兩個進程, 一個主進程, 一個子進程, fork后面所有的代碼都是共享的, 雖然通過fork的返回值可以判斷是主進程還是子進程來執(zhí)行相應(yīng)的子進程或主進程邏輯,但之后子進程自己又走到了for循環(huán)的部分, 子進程自己有創(chuàng)建了子進程, 所以上面看到了多個child_process 文件, 至于為什么是7個,
來分析一下。
=====================華麗的分割線=============================
循環(huán)變量$i, 當(dāng)$i為0時, 會產(chǎn)生一個主進程a(不變)和一個子進程aa,這個子進程創(chuàng)建了一個子進程文件,即fork_child_process_0_62656_62658_39, 主進程a繼續(xù)循環(huán), 即$i=1, 又創(chuàng)建了一個子進程ab, 他創(chuàng)建了fork_child_process_1_62656_62659_51, 主進程a繼續(xù)循環(huán)$i=2, 又創(chuàng)建了一個子進程ac, 他創(chuàng)建了fork_child_process_2_62656_62661_91這里可以看到62656就是主進程a的pid.
至此, 主進程a的循環(huán)完畢, 在看看a創(chuàng)建的第一個子進程aa, aa在創(chuàng)建之后, 創(chuàng)建好了上面的子進程文件之后并不會什么也不做, 他也會繼續(xù)走for的循環(huán), 而且繼承了主進程a的循環(huán)變量, 也就是$i的值為0,所以aa進程下一次的循環(huán)的$i就是1, 然后aa繼續(xù)創(chuàng)建了子進程aaa,從而創(chuàng)建文件fork_child_process_1_62658_62660_22,aa繼續(xù),$i=2, 又創(chuàng)建了一個子進程aab, 這個子進程創(chuàng)建了文件fork_child_process_2_62658_62662_22, 這里可以看到aaa和aab的ppid就是aa的pid 62658,
同理aaa,aab 也繼承了aa的$i值,這時$i的值為1, 當(dāng)繼續(xù)循環(huán)時, $i 就變成了2, 也就只能循環(huán)一次了,相應(yīng)aaa,aab 創(chuàng)建了子進程文件fork_child_process_2_62659_62663_82(aaaa),fork_child_process_2_62660_62664_59(aaba),而他們相應(yīng)的父進程就是aaa(62659)和aab(62660).
至此, for循環(huán)中的多進程邏輯完成了, 也就是為何產(chǎn)生了第一部分的7個文件
=====================華麗的分割線=============================
而至于為何第二部分是8個文件, 各位可以自己思考一下, 注意, 無論主進程還是子進程, 在for循環(huán)完畢之后會繼續(xù)往下走, 知道這一點就好理解了。
在實際的代碼中, 我就犯了這種錯誤。
那如何解決上面的問題呢, 只要在子進程執(zhí)行的最后exit就好啦,
fork_child_process_0_63219_63221_66 fork_child_process_1_63219_63222_88 fork_child_process_2_63219_63223_22 fork_process_pid_62225_63219_77
繼續(xù),那么在網(wǎng)上看到很多多進程編程中使用pcntl_waitpid, 并不了解他是做什么的,且相應(yīng)的例子很少, 我暫且來說說我的理解
pcntl_waitpid等待或返回fork的子進程狀態(tài)。
多進程的主進程創(chuàng)建了子進程,那主進程如何確認(rèn)子進程的狀態(tài)呢。 假如主進程需要根據(jù)子進程的狀態(tài)做不同的處理呢, 這里的狀態(tài)包括子進程被kill掉,或變成僵尸進程等。 pcntl_waitpid就可以獲取子進程的狀態(tài)碼, 通過這個狀態(tài)碼, 就可知道子進程處于什么狀態(tài)
他的用法:
int pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] )
返回的值可以是-1,0或者 >0的值, 如果是-1, 表示子進程出錯, 如果>0表示子進程已經(jīng)退出且值是退出的子進程pid,至于如何退出, 可以通過$status狀態(tài)碼反應(yīng)。 那什么時候返回0呢, 只有在option 參數(shù)為 WNOHANG且子進程正在運行時0, 也就是說當(dāng)設(shè)置了options=WNOHANG時, 如果子進程還沒有退出, 此時pcntl_waitpid就會返回0
另外, 如果不設(shè)置這個參數(shù)為WNOHANG, pcntl_waitpid 就會阻塞運行, 直到子進程退出, 至于option的另外一個值WUNTRACED, 暫未理解, 不表
那么如何根據(jù)$status(狀態(tài)碼)判斷進程是如何退出呢, 如下(參數(shù)都是$status)
pcntl_wifexited這個函數(shù)可以根據(jù)$status 判斷進程是否正常退出, 何為正常退出, 比如exit
pcntl_wexitstatus這個函數(shù)僅在pcntl_wifexited 返回True(即正常退出)時有效, 且返回子進程退出的返回狀態(tài)碼, 這個返回狀態(tài)碼可以通過exit($s)的參數(shù)($s必須為整數(shù)時)定義
pcntl_wifsignaled檢查子進程狀態(tài)碼是否代表由于某個信號而中斷, 比如是不是我們給他發(fā)送了term, int 等信號了
pcntl_wexitstatus假如是發(fā)送信號而導(dǎo)致子進程中斷, 那么這個信號是什么信號呢, 這個函數(shù)就是獲取這個信號的
pcntl_wifstopped僅當(dāng)option選項為WUNTRACED時有效, 未理解, 不表
pcntl_wtermsig同上
綜合實例代碼:
$res = pcntl_waitpid($pid, $status, WNOHANG); //FileLog::log("pid is $pid; wait result is $res"); if($res == -1 || $res > 0){ if(!pcntl_wifexited($status)){ //進程非正常退出 FileLog::log("service stop unusally; pid is $pid"); }else{ //獲取進程終端的退出狀態(tài)碼; $code = pcntl_wexitstatus($status); FileLog::log("service stop code: $code;pid is $pid "); } if(pcntl_wifsignaled($status)){ //不是通過接受信號中斷 FileLog::log("service stop not by signal;pid is $pid "); }else{ $signal = pcntl_wtermsig($status); FileLog::log("service stop by signal $signal;pid is $pid"); } }
上面的這個代碼就通過根據(jù)pcntl_waitpid的返回結(jié)果和狀態(tài)碼對子進程因為不同原因中斷做了不同的處理
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/21087.html
摘要:多進程中與多進程相關(guān)的兩個重要拓展是和。函數(shù)執(zhí)行期間,主進程除了等待無法處理其他任務(wù),所以一般不認(rèn)為這是多進程編程?;厥兆舆M程有兩種方式,一種是主進程調(diào)用函數(shù)等待子進程結(jié)束另外一種是處理信號。 轉(zhuǎn)載請注明文章出處: https://tlanyan.me/php-review... PHP回顧系列目錄 PHP基礎(chǔ) web請求 cookie web響應(yīng) session 數(shù)據(jù)庫操作 加解...
摘要:說明函數(shù)創(chuàng)建一個子進程,這個子進程僅進程號和父進程號與其父進程不同。返回值成功時,在父進程執(zhí)行線程內(nèi)返回產(chǎn)生的子進程的,在子進程執(zhí)行線程內(nèi)返回。失敗時,在父進程上下文返回,不會創(chuàng)建子進程,并且會引發(fā)一個錯誤。 pcntl 簡介 PHP的進程控制支持實現(xiàn)了Unix方式的進程創(chuàng)建, 程序執(zhí)行, 信號處理以及進程的中斷。 進程控制不能被應(yīng)用在Web服務(wù)器環(huán)境,當(dāng)其被用于Web服務(wù)環(huán)境時可能會...
摘要:職場多年下來,技術(shù)也算是逐漸地有些積累,但是更重要的是對自身有了更加合理的人生定位?;蛟S,人生的意義,就在于此處的感悟吧?;诘牟l(fā)處理封裝類。對語言底層擴展的的深度解讀和生產(chǎn)應(yīng)用。函數(shù)官網(wǎng)手冊中對的說明,更細化的需求可以研究深化。 個人聲明 作者:于立(wx/yulichenr) 敬告:聯(lián)系我,請注明來源和來意 本人開發(fā)有很多年了,但是很少整理分享,如今趁著清閑就為大家服務(wù)了,希...
摘要:第一次子進程正在休眠中,父進程依舊在循環(huán)中。第三次此時父進程已經(jīng)執(zhí)行了,將已經(jīng)退出的子進程回收,釋放了等資源。梳理一下流程,子進程向父進程發(fā)送信號是對人們來說是透明的,也就是說我們無須關(guān)心。 [原文地址:https://blog.ti-node.com/blog...] 上一篇尬聊了通篇的pcntl_wait()和pcntl_waitpid(),就是為了解決僵尸進程的問題,但最后看起來...
閱讀 2141·2021-11-24 09:39
閱讀 1518·2019-08-30 15:44
閱讀 1974·2019-08-29 17:06
閱讀 3428·2019-08-29 16:32
閱讀 3570·2019-08-29 16:26
閱讀 2679·2019-08-29 15:35
閱讀 3047·2019-08-29 12:50
閱讀 1667·2019-08-29 11:15