PHP多進程編程之僵尸進程問題
來源:原創(chuàng) 時間:2017-10-17 瀏覽:0 次 經(jīng)過運用pcntl_fork函數(shù),我們現(xiàn)已有了新的子進程,而子進程接下來完結(jié)我們需求處理的內(nèi)容,那么我們就暫時叫做service()吧,而且我們需求很多個service()進行處理,再次參照我們之前的需求,父進程需求一向循環(huán)讀取配置文件,等候文件發(fā)作改動。經(jīng)過對pcntl_fork的辦法,很簡單我們就能夠?qū)懗鋈缦麓a:
$res = config();//kill進程
for($i = 0; $i < $res[sum]; $i++) {
$pid = pcntl_fork();
if ($pid == 0) {
service();
return;
}
}
代碼中注釋的當?shù)匚覀冃枨笤谂渲梦募邪l(fā)作改動的時分殺死進程,殺死進程的的辦法很簡單,能夠運用kill指令直接殺死,比方(假定pid為123):
1 kill 123
可是我們發(fā)現(xiàn),運用這個殺死進程的辦法并沒有真實的把進程殺死,這個子進程被殺身后還占用這個進程的資源,我們成為僵尸進程,僵尸進程是運用kill指令無法殺死的。想要處理這個問題,我們能做的只要兩種辦法。
1. shutdown
2. 殺死該進程的父進程。
可是這兩種辦法都不可,由于這個程序的意圖是監(jiān)控常駐在服務(wù)器內(nèi),服務(wù)器不能封閉,而且父進程也不能被干掉。這時分我們看到了官方文檔關(guān)于fork辦法的解說:
1 pcntl_wait($status); //等候子進程中止,避免子進程成為僵尸進程。
本來有種辦法能夠避免進程成為僵尸進程,可是,官網(wǎng)給出的代碼是這姿態(tài)的:
1 $pid = pcntl_fork();
2 //父進程和子進程都會履行下面代碼
3 if ($pid == -1) {
4 //錯誤處理:創(chuàng)立子進程失利時回來-1.
5 die('could not fork');
6 } else if ($pid) {
7 //父進程會得到子進程號,所以這兒是父進程履行的邏輯
8 pcntl_wait($status); //等候子進程中止,避免子進程成為僵尸進程。
9 } else {
10 //子進程得到的$pid為0, 所以這兒是子進程履行的邏輯。
11 }
什么意思呢?就是父進程會等候子進程運轉(zhuǎn),等子進程運轉(zhuǎn)完畢之后,才會進行下一步,而且也會消除僵尸進程。可是這兒又和我們的需求不符合了,我們的子進程為一個死循環(huán)的程序,不斷的查找輸出,更本沒有完畢的時分,而且我們需求的是異步處理而不是同步。可是這個辦法能夠用嗎?其實當然能夠。
在pcntl_wait的文檔中是這么解說這個函數(shù)的:
wait函數(shù)刮起當時進程的履行直到一個子進程退出或接收到一個信號要求中止當時進程或調(diào)用一個信號處理函數(shù)。 如果一個子進程在調(diào)用此函數(shù)時現(xiàn)已退出(俗稱僵尸進程),此函數(shù)馬上回來。子進程運用的一切體系資源將 被開釋。關(guān)于wait在您體系上作業(yè)的具體標準請查看您體系的wait(2)手冊。
我們發(fā)現(xiàn),當這個函數(shù)發(fā)現(xiàn)子進程成為了僵尸進程就會開釋僵尸進程的資源——條件是這個僵尸進程為這個父進程的子進程。那么我們就能夠奇妙的運用這個辦法讓這些僵尸進程開釋資源了,所以就有了如下代碼:
1 posix_kill(123, 9);
2 pcntl_wait($status);
這樣我們先運用kill干掉這個進程,這個進程就不會再運轉(zhuǎn)了,可是這個進程成為了僵尸進程,占用著資源,我們下一句就履行一次pcntl_wait()讓這些僵尸進程開釋資源,這樣,子進程才真實的被停止了,僵尸進程被消除了。