請(qǐng)教一下,在workerman發(fā)送信號(hào)SIGINT給主進(jìn)程,主進(jìn)程(pcntl_wait)會(huì)立刻收到信號(hào)并執(zhí)行信號(hào)處理函數(shù),
我模擬了下,主進(jìn)程(pcntl_wait)會(huì)一直阻塞,并不會(huì)立刻執(zhí)行信號(hào)處理函數(shù),信號(hào)已經(jīng)注冊(cè)入隊(duì)列當(dāng)中了。假設(shè)我發(fā)送了好幾次信號(hào),最終如果按control+c中斷的時(shí)候,就會(huì)輸出這幾次信號(hào)的處理函數(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ā)送了好幾次信號(hào),仍然阻塞,最后以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
因?yàn)橹鬟M(jìn)程阻塞在pcntl_wait,除非是子進(jìn)程退出,那么主進(jìn)程才會(huì)繼續(xù)下一步,才有可能主動(dòng)pcntl_signal_dispatch檢查信號(hào)。如果發(fā)送信號(hào)給主進(jìn)程,主進(jìn)程還是阻塞在pcntl_wait呢,沒法觸發(fā)pcntl_signal_dispatch.>.<
pcntl_wait其實(shí)就是wait系統(tǒng)調(diào)用,是可以被信號(hào)打斷的,當(dāng)信號(hào)到來后pcntl_wait會(huì)立刻返回。
同理sleep也是系統(tǒng)調(diào)用,也可以被信號(hào)打斷停止睡眠立刻返回。
所以在pcntl_wait或者sleep下的pcntl_signal_dispatch函數(shù)在收到信號(hào)后會(huì)立刻被執(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";
//被信號(hào)打斷
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個(gè)參數(shù)時(shí),子進(jìn)程的sleep會(huì)被信號(hào)打斷,父進(jìn)程的wait為啥不會(huì)被打斷呢?只是把信號(hào)加入隊(duì)列
恩恩,我就是這點(diǎn)疑惑,我利用另外的一個(gè)程序,像主進(jìn)程發(fā)送了SIGINT信號(hào),但是他并不會(huì)被打斷,只會(huì)將信號(hào)加入信號(hào)隊(duì)列。
看了下兩位的回復(fù),感覺其中是有問題的。樓主的問題是“在workerman發(fā)送信號(hào)SIGINT給主進(jìn)程,主進(jìn)程(pcntl_wait)會(huì)立刻收到信號(hào)并執(zhí)行信號(hào)處理函數(shù)”,而在示例代碼中的邏輯比較混亂。在walkor給出的答案里說到了子進(jìn)程添加pcntl_signal_dispatch(),但是注冊(cè)信號(hào)回調(diào)的代碼缺是在主進(jìn)程。最后貼一下描述“在workerman發(fā)送信號(hào)SIGINT給主進(jìn)程,主進(jìn)程(pcntl_wait)會(huì)立刻收到信號(hào)并執(zhí)行信號(hào)處理函數(shù)”的代碼,如有不正確的地方請(qǐng)多多指教:
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()的第三個(gè)參數(shù),設(shè)置未false,也就是說,系統(tǒng)調(diào)用不自動(dòng)重新啟動(dòng),可以收到信號(hào),這個(gè)不理解
設(shè)置為true的話,wait會(huì)再次被自動(dòng)調(diào)用,導(dǎo)致進(jìn)程再次阻塞;另外一次信號(hào)只能中斷一次系統(tǒng)調(diào)用。