僵尸行程
當子行程運行結束,父行程仍然繼續運行,但父行程沒有對子行程進行回收,釋放子行程占用的資源,此時子行程就成為了一個僵尸行程,
在Unix行程管理中,如果新開的子行程運行結束,父行程將會收到一個SIGCHLD信號,子行程暫時成為僵尸行程,等待父行程進行處理,如果父行程一直不處理,該行程將會一直存在,占用系統行程表項,永久成為僵尸行程,如果僵尸行程過多,導致系統沒有可用的行程表項,將無法運行其他的應用程式,
<?php
$str = "hello world!" . PHP_EOL;
$pid = pcntl_fork();
if ($pid > 0) {
echo "我是主行程,id是" . getmypid() . ",子行程的pid是{$pid}" . PHP_EOL;
pcntl_async_signals(true);
pcntl_signal(SIGCHLD, function () {
echo '子行程退出了,請及時處理' . PHP_EOL;
});
while (1) { //模擬主行程一直運行
sleep(1);
}
} elseif($pid==0) {
echo "我是子行程,我的pid是". getmypid() ."\n";
}else{
echo "我是主行程,開啟子行程失敗\n";
}
使用ps查看僵尸行程:
ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'
終端會輸出:
Z+ 7136 7137 [php] <defunct>
當主行程退出之后,子行程將會被init接管并處理
使用 pcntl_wait 回收僵尸行程:
<?php
echo time() . PHP_EOL;
$pid = pcntl_fork();
if ($pid > 0) { //主行程代碼
pcntl_wait($status); //父行程阻塞方式等待子行程的退出
echo time() . PHP_EOL;
} elseif($pid==0) {
sleep(3);
echo "我是子行程,我的pid是". getmypid() ."\n";
exit();
}else{
die("我是主行程,開啟子行程失敗\n");
}
1589874657
我是子行程,我的pid是16140
1589874660
pcntl_wait($status); 默認為阻塞方式回收子行程,可以設定第二個引數為 WNOHANG 即為非阻塞方式回收子行程,代碼會繼續往下執行,子行程退出后會自動回收,
多個子行程只需要一個pcntl_wait即可回收完成,
在父行程中,為SIGCHLD配置handler來回收:
<?php
pcntl_async_signals(true);
pcntl_signal(SIGCHLD, function () {
echo "SIGCHLD" . PHP_EOL;
pcntl_wait($status); //父行程阻塞方式等待子行程的退出
});
echo time() . PHP_EOL;
$pid = pcntl_fork();
if ($pid > 0) { //主行程代碼
sleep(10);
echo time() . PHP_EOL;
} elseif($pid==0) {
sleep(3);
echo "我是子行程,我的pid是". getmypid() ."\n";
exit;
}else{
die("我是主行程,開啟子行程失敗\n");
}
1589874039
我是子行程,我的pid是12875
SIGCHLD
1589874040
忽略子行程結束信號,由init回收:
<?php
pcntl_async_signals(true);
pcntl_signal(SIGCHLD, SIG_IGN);
echo time() . PHP_EOL;
$pid = pcntl_fork();
if ($pid > 0) { //主行程代碼
sleep(10);
echo time() . PHP_EOL;
} elseif($pid==0) {
sleep(3);
echo "我是子行程,我的pid是". getmypid() ."\n";
exit;
} else {
die("我是主行程,開啟子行程失敗\n");
}
1589874331
1589874331
我是子行程,我的pid是14493
孤兒行程
孤兒行程是指在其父行程執行完成或被終止后仍繼續運行的一類行程,這些孤兒行程將被init行程收養,并由init行程對它們完成回收作業,
孤兒行程沒有任何危害,只需要注意自己的代碼邏輯即可,
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('fork error');
} elseif ($pid > 0) {
echo "爸爸先走了,兒子你好好干活" . PHP_EOL;
exit(); // 主行程在很短的時間內已經退出
} else {
// 子行程繼續運行
$i = 10;
while($i) {
echo $i;
$i--;
sleep(1);
}
}
爸爸先走了,兒子你好好干活
1111111111...
孤兒行程與僵尸行程的區別
僵尸行程:一個子行程在其父行程還沒有呼叫wait()或waitpid()的情況下退出,這個子行程就是僵尸行程,任何一個子行程在退出之后,并非馬上就消失掉,而是留下一個稱為僵尸行程的資料結構,等待父行程處理,這是每個子行程在結束時都要經過的階段,如果子行程在退出之后,父行程沒有來得及處理,那么子行程就不會釋放,其行程號就會一直被占用,但是系統所能使用的行程號是有限的,如果大量的產生僵尸行程,將因為沒有可用的行程號而導致系統不能產生新的行程,此為僵尸行程的危害,應當避免,
孤兒行程:一個父行程退出,而它的一個或多個子行程還在運行,那么那些子行程將成為孤兒行程,孤兒行程將被init行程收養,并由init行程對它們完成回收作業,每當一個孤兒行程出現,內核就把孤 兒行程的父行程設定為init,而init行程會回圈地wait()已經退出的子行程,這樣,當一個孤兒行程結束其生命周期的時候,init行程就會進行回收作業,因此孤兒行程并不會有什么危害 ,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/36374.html
標籤:PHP
上一篇:php字串基礎教程
