




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第什么是PHP7中的孤兒進(jìn)程與僵尸進(jìn)程我們知道在unix/linux中,正常情況下,子進(jìn)程是通過父進(jìn)程創(chuàng)建的,子進(jìn)程在創(chuàng)建新的進(jìn)程。子進(jìn)程的結(jié)束和父進(jìn)程的運(yùn)行是一個異步過程,即父進(jìn)程永遠(yuǎn)無法預(yù)測子進(jìn)程到底什么時候結(jié)束。當(dāng)一個進(jìn)程完成它的工作終止之后,它的父進(jìn)程需要調(diào)用wait()或者waitpid()系統(tǒng)調(diào)用取得子進(jìn)程的終止?fàn)顟B(tài)。
孤兒進(jìn)程
一個父進(jìn)程退出,而它的一個或多個子進(jìn)程還在運(yùn)行,那么那些子進(jìn)程將成為孤兒進(jìn)程。孤兒進(jìn)程將被init進(jìn)程(進(jìn)程號為1)所收養(yǎng),并由init進(jìn)程對它們完成狀態(tài)收集工作。
僵尸進(jìn)程
一個進(jìn)程使用fork創(chuàng)建子進(jìn)程,如果子進(jìn)程退出,而父進(jìn)程并沒有調(diào)用wait或waitpid獲取子進(jìn)程的狀態(tài)信息,那么子進(jìn)程的進(jìn)程描述符仍然保存在系統(tǒng)中。這種進(jìn)程稱之為僵死進(jìn)程。
問題及危害
unix提供了一種機(jī)制可以保證只要父進(jìn)程想知道子進(jìn)程結(jié)束時的狀態(tài)信息,就可以得到。這種機(jī)制就是:在每個進(jìn)程退出的時候,內(nèi)核釋放該進(jìn)程所有的資源,包括打開的文件,占用的內(nèi)存等。但是仍然為其保留一定的信息(包括進(jìn)程號theprocessID,退出狀態(tài)theterminationstatusoftheprocess,運(yùn)行時間theamountofCPUtimetakenbytheprocess等)。直到父進(jìn)程通過wait/waitpid來取時才釋放。但這樣就導(dǎo)致了問題,如果進(jìn)程不調(diào)用wait/waitpid的話,那么保留的那段信息就不會釋放,其進(jìn)程號就會一直被占用,但是系統(tǒng)所能使用的進(jìn)程號是有限的,如果大量的產(chǎn)生僵死進(jìn)程,將因?yàn)闆]有可用的進(jìn)程號而導(dǎo)致系統(tǒng)不能產(chǎn)生新的進(jìn)程.此即為僵尸進(jìn)程的危害,應(yīng)當(dāng)避免。
孤兒進(jìn)程是沒有父進(jìn)程的進(jìn)程,孤兒進(jìn)程這個重任就落到了init進(jìn)程身上,init進(jìn)程就好像是一個民政局,專門負(fù)責(zé)處理孤兒進(jìn)程的善后工作。每當(dāng)出現(xiàn)一個孤兒進(jìn)程的時候,內(nèi)核就把孤兒進(jìn)程的父進(jìn)程設(shè)置為init,而init進(jìn)程會循環(huán)地wait()它的已經(jīng)退出的子進(jìn)程。這樣,當(dāng)一個孤兒進(jìn)程凄涼地結(jié)束了其生命周期的時候,init進(jìn)程就會代表黨和政府出面處理它的一切善后工作。因此孤兒進(jìn)程并不會有什么危害。
任何一個子進(jìn)程(init除外)在exit()之后,并非馬上就消失掉,而是留下一個稱為僵尸進(jìn)程(Zombie)的數(shù)據(jù)結(jié)構(gòu),等待父進(jìn)程處理。這是每個子進(jìn)程在結(jié)束時都要經(jīng)過的階段。如果子進(jìn)程在exit()之后,父進(jìn)程沒有來得及處理,這時用ps命令就能看到子進(jìn)程的狀態(tài)是“Z”。如果父進(jìn)程能及時處理,可能用ps命令就來不及看到子進(jìn)程的僵尸狀態(tài),但這并不等于子進(jìn)程不經(jīng)過僵尸狀態(tài)。如果父進(jìn)程在子進(jìn)程結(jié)束之前退出,則子進(jìn)程將由init接管。init將會以父進(jìn)程的身份對僵尸狀態(tài)的子進(jìn)程進(jìn)行處理。
僵尸進(jìn)程危害場景
例如有個進(jìn)程,它定期的產(chǎn)生一個子進(jìn)程,這個子進(jìn)程需要做的事情很少,做完它該做的事情之后就退出了,因此這個子進(jìn)程的生命周期很短,但是,父進(jìn)程只管生成新的子進(jìn)程,至于子進(jìn)程退出之后的事情,則一概不聞不問,這樣,系統(tǒng)運(yùn)行上一段時間之后,系統(tǒng)中就會存在很多的僵死進(jìn)程,倘若用ps命令查看的話,就會看到很多狀態(tài)為Z的進(jìn)程。嚴(yán)格地來說,僵死進(jìn)程并不是問題的根源,罪魁禍?zhǔn)资钱a(chǎn)生出大量僵死進(jìn)程的那個父進(jìn)程。因此,當(dāng)我們尋求如何消滅系統(tǒng)中大量的僵死進(jìn)程時,答案就是把產(chǎn)生大量僵死進(jìn)程的那個元兇槍斃掉(也就是通過kill發(fā)送SIGTERM或者SIGKILL信號啦)。槍斃了元兇進(jìn)程之后,它產(chǎn)生的僵死進(jìn)程就變成了孤兒進(jìn)程,這些孤兒進(jìn)程會被init進(jìn)程接管,init進(jìn)程會wait()這些孤兒進(jìn)程,釋放它們占用的系統(tǒng)進(jìn)程表中的資源,這樣,這些已經(jīng)僵死的孤兒進(jìn)程就能瞑目而去了。
孤兒進(jìn)程和僵尸進(jìn)程測試
1、孤兒進(jìn)程被init進(jìn)程收養(yǎng)
$pid=pcntl_fork();
if($pid0){
//顯示父進(jìn)程的進(jìn)程ID,這個函數(shù)可以是getmypid(),也可以用posix_getpid()
echo"FatherPID:".getmypid().PHP_EOL;
//讓父進(jìn)程停止兩秒鐘,在這兩秒內(nèi),子進(jìn)程的父進(jìn)程ID還是這個父進(jìn)程
sleep(2);
}elseif(0==$pid){
//讓子進(jìn)程循環(huán)10次,每次睡眠1s,然后每秒鐘獲取一次子進(jìn)程的父進(jìn)程進(jìn)程ID
for($i=1;$i=10;$i++){
sleep(1);
//posix_getppid()函數(shù)的作用就是獲取當(dāng)前進(jìn)程的父進(jìn)程進(jìn)程ID
echoposix_getppid().PHP_EOL;
}else{
echo"forkerror.".PHP_EOL;
}
測試結(jié)果:
phpdaemo001.php
FatherPID:18046
18046
18046
www@iZ2zec3dge6rwz2uw4tveuZ:~/test$1
1
2、僵尸進(jìn)程和危害
執(zhí)行以下代碼phpzombie1.php
$pid=pcntl_fork();
if($pid0){
//下面這個函數(shù)可以更改php進(jìn)程的名稱
cli_set_process_title('phpfatherprocess');
//讓主進(jìn)程休息60秒鐘
sleep(60);
}elseif(0==$pid){
cli_set_process_title('phpchildprocess');
//讓子進(jìn)程休息10秒鐘,但是進(jìn)程結(jié)束后,父進(jìn)程不對子進(jìn)程做任何處理工作,這樣這個子進(jìn)程就會變成僵尸進(jìn)程
sleep(10);
}else{
exit('forkerror.'.PHP_EOL);
}
執(zhí)行結(jié)果,另外一個終端窗口
www@iZ2zec3dge6rwz2uw4tveuZ:~$ps-aux|grep-v"grep\|nginx\|php-fpm"|grepphp
www184580.51.220406825920pts/1S+16:340:00phpfatherprocess
www184590.00.32040686656pts/1S+16:340:00phpchildprocess
www@iZ2zec3dge6rwz2uw4tveuZ:~$ps-aux|grep-v"grep\|nginx\|php-fpm"|grepphp
www184580.01.220406825920pts/1S+16:340:00phpfatherprocess
www184590.00.000pts/1Z+16:340:00[php]defunct
通過執(zhí)行ps-aux命令可以看到,當(dāng)程序在前十秒內(nèi)運(yùn)行的時候,phpchildprocess的狀態(tài)列為[S+],然而在十秒鐘過后,這個狀態(tài)變成了[Z+],也就是變成了危害系統(tǒng)的僵尸進(jìn)程。
那么,問題來了?如何避免僵尸進(jìn)程呢?
PHP通過pcntl_wait()和pcntl_waitpid()兩個函數(shù)來幫我們解決這個問題。了解Linux系統(tǒng)編程的應(yīng)該知道,看名字就知道這其實(shí)就是PHP把C語言中的wait()和waitpid()包裝了一下。
通過代碼演示pcntl_wait()來避免僵尸進(jìn)程。
pcntl_wait()函數(shù):
這個函數(shù)的作用就是“等待或者返回子進(jìn)程的狀態(tài)”,當(dāng)父進(jìn)程執(zhí)行了該函數(shù)后,就會阻塞掛起等待子進(jìn)程的狀態(tài)一直等到子進(jìn)程已經(jīng)由于某種原因退出或者終止。
換句話說就是如果子進(jìn)程還沒結(jié)束,那么父進(jìn)程就會一直等等等,如果子進(jìn)程已經(jīng)結(jié)束,那么父進(jìn)程就會立刻得到子進(jìn)程狀態(tài)。這個函數(shù)返回退出的子進(jìn)程的進(jìn)程ID或者失敗返回-1。
執(zhí)行以下代碼zombie2.php
$pid=pcntl_fork();
if($pid0){
//下面這個函數(shù)可以更改php進(jìn)程的名稱
cli_set_process_title('phpfatherprocess');
//返回$wait_result,就是子進(jìn)程的進(jìn)程號,如果子進(jìn)程已經(jīng)是僵尸進(jìn)程則為0
//子進(jìn)程狀態(tài)則保存在了$status參數(shù)中,可以通過pcntl_wexitstatus()等一系列函數(shù)來查看$status的狀態(tài)信息是什么
$wait_result=pcntl_wait($status);
print_r($wait_result);
print_r($status);
//讓主進(jìn)程休息60秒鐘
sleep(60);
}elseif(0==$pid){
cli_set_process_title('phpchildprocess');
//讓子進(jìn)程休息10秒鐘,但是進(jìn)程結(jié)束后,父進(jìn)程不對子進(jìn)程做任何處理工作,這樣這個子進(jìn)程就會變成僵尸進(jìn)程
sleep(10);
}else{
exit('forkerror.'.PHP_EOL);
}
在另外一個終端中通過ps-aux查看,可以看到在前十秒內(nèi),phpchildprocess是[S+]狀態(tài),然后十秒鐘過后進(jìn)程消失了,也就是被父進(jìn)程回收了,沒有變成僵尸進(jìn)程。
www@iZ2zec3dge6rwz2uw4tveuZ:~/test$ps-aux|grep-v"grep\|nginx\|php-fpm"|grepphp
www@iZ2zec3dge6rwz2uw4tveuZ:~/test$ps-aux|grep-v"grep\|nginx\|php-fpm"|grepphp
www185190.51.220406825576pts/1S+16:420:00phpfatherprocess
www185200.00.32040686652pts/1S+16:420:00phpchildprocess
www@iZ2zec3dge6rwz2uw4tveuZ:~/test$ps-aux|grep-v"grep\|nginx\|php-fpm"|grepphp
www185190.01.220406825576pts/1S+16:420:00phpfatherprocess
但是,pcntl_wait()有個很大的問題,就是阻塞。父進(jìn)程只能掛起等待子進(jìn)程結(jié)束或終止,在此期間父進(jìn)程什么都不能做,這并不符合多快好省原則,所以pcntl_waitpid()閃亮登場。pcntl_waitpid(pid,status,$option=0)的第三個參數(shù)如果設(shè)置為WNOHANG,那么父進(jìn)程不會阻塞一直等待到有子進(jìn)程退出或終止,否則將會和pcntl_wait()的表現(xiàn)類似。
修改第三個案例的代碼,但是,我們并不添加WNOHANG,演示說明pcntl_waitpid()功能:
$pid=pcntl_fork();
if($pid0){
//下面這個函數(shù)可以更改php進(jìn)程的名稱
cli_set_process_title('phpfatherprocess');
//返回值保存在$wait_result中
//$pid參數(shù)表示子進(jìn)程的進(jìn)程ID
//子進(jìn)程狀態(tài)則保存在了參數(shù)$status中
//將第三個option參數(shù)設(shè)置為常量WNOHANG,則可以避免主進(jìn)程阻塞掛起,此處父進(jìn)程將立即返回繼續(xù)往下執(zhí)行剩下的代碼
$wait_result=pcntl_waitpid($pid,$status);
var_dump($wait_result);
var_dump($status);
//讓主進(jìn)程休息60秒鐘
sleep(60);
}elseif(0==$pid){
cli_set_process_title('phpchildprocess');
//讓子進(jìn)程休息10秒鐘,但是進(jìn)程結(jié)束后,父進(jìn)程不對子進(jìn)程做任何處理工作,這樣這個子進(jìn)程就會變成僵尸進(jìn)程
sleep(10);
}else{
exit('forkerror.'.PHP_EOL);
}
下面是運(yùn)行結(jié)果,一個執(zhí)行phpzombie3.php程序的終端窗口
www@iZ2zec3dge6rwz2uw4tveuZ:~/test$phpzombie3.php
int(18586)
int(0)
^C
ctrl-c發(fā)送SIGINT信號給前臺進(jìn)程組中的所有進(jìn)程。常用于終止正在運(yùn)行的程序。
下面是ps-aux終端窗口
www@iZ2zec3dge6rwz2uw4tveuZ:~$ps-aux|grep-v"grep\|nginx\|php-fpm"|grepphp
www186050.31.220406825756pts/1S+16:520:00phpfatherprocess
www186060.00.32040686636pts/1S+16:520:00phpchildprocess
www@iZ2zec3dge6rwz2uw4tveuZ:~$ps-aux|grep-v"grep\|nginx\|php-fpm"|grepphp
www186050.11.220406825756pts/1S+16:520:00phpfatherprocess
www@iZ2zec3dge6rwz2uw4tveuZ:~$ps-aux|grep-v"grep\|nginx\|php-fpm"|grepphp
www186050.01.220406825756pts/1S+16:520:00phpfatherprocess
www@iZ2zec3dge6rwz2uw4tveuZ:~$ps-aux|grep-v"grep\|nginx\|php-fpm"|grepphp//ctrl-c后不再被阻塞
www@iZ2zec3dge6rwz2uw4tveuZ:~$
實(shí)際上可以看到主進(jìn)程是被阻塞的,一直到第十秒子進(jìn)程退出了,父進(jìn)程不再阻塞
修改第四段代碼,添加第三個參數(shù)WNOHANG,代碼如下:
$pid=pcntl_fork();
if($pid0){
//下面這個函數(shù)可以更改php進(jìn)程的名稱
cli_set_process_title('phpfatherprocess');
//返回值保存在$wait_result中
//$pid參數(shù)表示子進(jìn)程的進(jìn)程ID
//子進(jìn)程狀態(tài)則保存在了參數(shù)$status中
//將第三個option參數(shù)設(shè)置為常量WNOHANG,則可以避免主進(jìn)程阻塞掛起,此處父進(jìn)程將立即返回繼續(xù)往下執(zhí)行剩下的代碼
$wait_result=pcntl_waitpid($pid,$status,WNOHANG);
var_dump($wait_result);
var_dump($status);
echo"不阻塞,運(yùn)行到這里".PHP_EOL;
//讓主進(jìn)程休息60秒鐘
sleep(60);
}elseif(0==$pid){
cli_set_process_title('phpchildprocess');
//讓子進(jìn)程休息10秒鐘,但是進(jìn)程結(jié)束后,父進(jìn)程不對子進(jìn)程做任何處理工作,這樣這個子進(jìn)程就會變成僵尸進(jìn)程
sleep(10);
}else{
exit('forkerror.'.PHP_EOL);
}
執(zhí)行phpzombie4.php
www@iZ2zec3dge6rwz2uw4tveuZ:~/test$phpzombie4.php
int(0)
int(0)
不阻塞,運(yùn)行到這里
另一個ps-aux終端窗口
www@iZ2zec3dge6rwz2uw4tveuZ:~$ps-aux|grep-v"grep\|nginx\|
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 數(shù)字智慧方案5494丨商業(yè)辦公綜合體智能化系統(tǒng)匯報(bào)方案
- 液壓馬達(dá)的振動與噪音抑制考核試卷
- 環(huán)境地質(zhì)工程課件
- 《能量分配器件》課件
- 2025年嘧菌酯合作協(xié)議書
- 小學(xué)勞動教育意義及建議
- 2025年工程瑞雷波儀項(xiàng)目建議書
- 2025年環(huán)境控制系統(tǒng)項(xiàng)目合作計(jì)劃書
- 2025年重癥監(jiān)護(hù)臨床信息系統(tǒng)項(xiàng)目建議書
- 醫(yī)學(xué)顯微鏡技術(shù)原理與應(yīng)用
- 新疆可克達(dá)拉職業(yè)技術(shù)學(xué)院招聘事業(yè)單位人員筆試真題2024
- 重慶金太陽2025屆高三5月聯(lián)考英語及答案
- 護(hù)理事業(yè)編試題及答案
- 全國新能源汽車關(guān)鍵技術(shù)技能大賽理論知識競賽題庫
- 2025屆貴州省遵義第四中學(xué)高考英語全真模擬密押卷含解析
- 人工氣道濕化管理
- 2025屆湖北省武漢市高中畢業(yè)生4月調(diào)研考試英語試題答案
- 人工智能在食品檢測中的創(chuàng)新應(yīng)用探討
- 2025-2030中國骨形態(tài)發(fā)生蛋白2行業(yè)市場發(fā)展趨勢與前景展望戰(zhàn)略研究報(bào)告
- 2025年高考語文備考之新題型:成語填空專項(xiàng)訓(xùn)練(含答案)
- 職場溝通職場溝通與人際關(guān)系處理知到課后答案智慧樹章節(jié)測試答案2025年春山東管理學(xué)院
評論
0/150
提交評論