请教一下,在workerman发送信号SIGINT给主进程,主进程(pcntl_wait)会立刻收到信号并执行信号处理函数,
我模拟了下,主进程(pcntl_wait)会一直阻塞,并不会立刻执行信号处理函数,信号已经注册入队列当中了。假设我发送了好几次信号,最终如果按control+c中断的时候,就会输出这几次信号的处理函数。
首先感谢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) ;
}
}
我发送了好几次信号,仍然阻塞,最后以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_signal_dispatch就好了。
信号回调不会自己自动执行的,要么有声明declare(ticks=1)要么调用主动pcntl_signal_dispatch检查信号。
加上也不会执行
因为主进程阻塞在pcntl_wait,除非是子进程退出,那么主进程才会继续下一步,才有可能主动pcntl_signal_dispatch检查信号。如果发送信号给主进程,主进程还是阻塞在pcntl_wait呢,没法触发pcntl_signal_dispatch.>.<
pcntl_wait其实就是wait系统调用,是可以被信号打断的,当信号到来后pcntl_wait会立刻返回。
同理sleep也是系统调用,也可以被信号打断停止睡眠立刻返回。
所以在pcntl_wait或者sleep下的pcntl_signal_dispatch函数在收到信号后会立刻被执行。
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个参数时,子进程的sleep会被信号打断,父进程的wait为啥不会被打断呢?只是把信号加入队列
php是7.3版本的
恩恩,我就是这点疑惑,我利用另外的一个程序,像主进程发送了SIGINT信号,但是他并不会被打断,只会将信号加入信号队列。
我再去理解理解,多谢boss
不客气
看了下两位的回复,感觉其中是有问题的。楼主的问题是“在workerman发送信号SIGINT给主进程,主进程(pcntl_wait)会立刻收到信号并执行信号处理函数”,而在示例代码中的逻辑比较混乱。在walkor给出的答案里说到了子进程添加pcntl_signal_dispatch(),但是注册信号回调的代码缺是在主进程。最后贴一下描述“在workerman发送信号SIGINT给主进程,主进程(pcntl_wait)会立刻收到信号并执行信号处理函数”的代码,如有不正确的地方请多多指教:
不错哦
可是上面的例子中
pcntl_signal_dispatch()
注释掉的话,也是正常的。为什么要在这个位置添加呢?经测试,主进程是在子进程退出后收到的信号,该改动无效
对的
请教一下walkor大侠,pcntl_wait第二个参数WUNTRACED具体表示什么意思呢?手册里的解释没太看懂
最终的解决办法是在pcntl_signal()的第三个参数,设置未false,也就是说,系统调用不自动重新启动,可以收到信号,这个不理解
设置为true的话,wait会再次被自动调用,导致进程再次阻塞;另外一次信号只能中断一次系统调用。