請教一下,在workerman發(fā)送信號SIGINT給主進程,主進程(pcntl_wait)會立刻收到信號并執(zhí)行信號處理函數(shù),
我模擬了下,主進程(pcntl_wait)會一直阻塞,并不會立刻執(zhí)行信號處理函數(shù),信號已經(jīng)注冊入隊列當(dāng)中了。假設(shè)我發(fā)送了好幾次信號,最終如果按control+c中斷的時候,就會輸出這幾次信號的處理函數(shù)。
首先感謝BOSS:),希望知道workerman是如何處理的,我看了好多次,還是找不出所以然-。-,太笨了。
代碼如下
function stopAll($sig){
echo "master has a sig $sig\n" ;
global $pid ;
echo $pid."\n" ;
if($pid > 0) {
posix_kill($pid,$sig) ;
}
}
$pid = pcntl_fork();
if($pid > 0)
{
pcntl_signal(SIGINT,'stopAll') ;
$epid = pcntl_wait($status,WUNTRACED);
$id = getmypid();
echo "parent process {$id}, child process {$pid}\n";
if($epid){
echo "child $epid exit \n" ;
}
pcntl_signal_dispatch();
}
else
{
$id = getmypid();
echo "child process,pid {$id}\n";
while(1){
sleep(2) ;
}
}
我發(fā)送了好幾次信號,仍然阻塞,最后以control+c中斷輸出如下:
qmoredeMacBook-Pro:120.25.105.202 Qmore$ php recive_sig.php
child process,pid 24793
^[[A^Cmaster has a sig 2
24793
master has a sig 2
24793
master has a sig 2
24793
master has a sig 2
24793
master has a sig 2
24793
parent process 24792, child process 24793
child 24793 exit
因為主進程阻塞在pcntl_wait,除非是子進程退出,那么主進程才會繼續(xù)下一步,才有可能主動pcntl_signal_dispatch檢查信號。如果發(fā)送信號給主進程,主進程還是阻塞在pcntl_wait呢,沒法觸發(fā)pcntl_signal_dispatch.>.<
pcntl_wait其實就是wait系統(tǒng)調(diào)用,是可以被信號打斷的,當(dāng)信號到來后pcntl_wait會立刻返回。
同理sleep也是系統(tǒng)調(diào)用,也可以被信號打斷停止睡眠立刻返回。
所以在pcntl_wait或者sleep下的pcntl_signal_dispatch函數(shù)在收到信號后會立刻被執(zhí)行。
echo posix_getpid().PHP_EOL;
pcntl_async_signals(true);
pcntl_signal(SIGINT, function(){
echo posix_getpid()." get signal ".date("H:i:s")."\n";
});
$pid = pcntl_fork();
if ($pid) {
E:
pcntl_wait($status, WUNTRACED);
echo pcntl_strerror(pcntl_get_last_error())." pcntl_wait return\n";
//被信號打斷
if(pcntl_get_last_error()==4){
goto E;
}
} else {
echo "son:".posix_getpid().PHP_EOL;
$i=0;
while(1){
echo date("H:i:s").PHP_EOL;
sleep(1);
$i++;
if($i>5){
exit(100);
}
}
}
這段代碼在pcntl_signal 不傳第3個參數(shù)時,子進程的sleep會被信號打斷,父進程的wait為啥不會被打斷呢?只是把信號加入隊列
看了下兩位的回復(fù),感覺其中是有問題的。樓主的問題是“在workerman發(fā)送信號SIGINT給主進程,主進程(pcntl_wait)會立刻收到信號并執(zhí)行信號處理函數(shù)”,而在示例代碼中的邏輯比較混亂。在walkor給出的答案里說到了子進程添加pcntl_signal_dispatch(),但是注冊信號回調(diào)的代碼缺是在主進程。最后貼一下描述“在workerman發(fā)送信號SIGINT給主進程,主進程(pcntl_wait)會立刻收到信號并執(zhí)行信號處理函數(shù)”的代碼,如有不正確的地方請多多指教:
function stopAll($sig){
echo "master has a sig $sig\n" ;
}
$master_id = getmypid();
$pid = pcntl_fork();
if($pid > 0)
{
pcntl_signal(SIGINT,'stopAll') ;
$epid = pcntl_wait($status,WUNTRACED);
pcntl_signal_dispatch();
echo "parent process {$master_id}, child process {$pid}\n";
if($epid){
echo "child $epid exit \n" ;
}
}
else
{
$id = getmypid();
echo "child process,pid {$id}\n";
sleep(6);
echo "send signal to master\n";
posix_kill($master_id, SIGINT);
}
最終的解決辦法是在pcntl_signal()的第三個參數(shù),設(shè)置未false,也就是說,系統(tǒng)調(diào)用不自動重新啟動,可以收到信號,這個不理解