关于pcntl_wait与信号中断触发的问题

0

请教一下,在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
已邀请:

walkor

赞同来自:

else
{
$id = getmypid();
echo "child process,pid {$id}\n";
while(1){
sleep(2) ;
pcntl_signal_dispatch();
}
}

需要在子进程部分及时检查信号并处理,加一句pcntl_signal_dispatch就好了。
信号回调不会自己自动执行的,要么有声明declare(ticks=1)要么调用主动pcntl_signal_dispatch检查信号。

Qmore泽 - 面包、牛奶会有的

赞同来自:

因为主进程阻塞在pcntl_wait,除非是子进程退出,那么主进程才会继续下一步,才有可能主动pcntl_signal_dispatch检查信号。如果发送信号给主进程,主进程还是阻塞在pcntl_wait呢,没法触发pcntl_signal_dispatch.>.<

walkor

赞同来自:

pcntl_wait其实就是wait系统调用,是可以被信号打断的,当信号到来后pcntl_wait会立刻返回。
同理sleep也是系统调用,也可以被信号打断停止睡眠立刻返回。
所以在pcntl_wait或者sleep下的pcntl_signal_dispatch函数在收到信号后会立刻被执行。

Qmore泽 - 面包、牛奶会有的

赞同来自:

恩恩,我就是这点疑惑,我利用另外的一个程序,像主进程发送了SIGINT信号,但是他并不会被打断,只会将信号加入信号队列。

Qmore泽 - 面包、牛奶会有的

赞同来自:

我再去理解理解,多谢boss

walkor

赞同来自:

不客气

soooldier

赞同来自:

看了下两位的回复,感觉其中是有问题的。楼主的问题是“在workerman发送信号SIGINT给主进程,主进程(pcntl_wait)会立刻收到信号并执行信号处理函数”,而在示例代码中的逻辑比较混乱。在walkor给出的答案里说到了子进程添加pcntl_signal_dispatch(),但是注册信号回调的代码缺是在主进程。最后贴一下描述“在workerman发送信号SIGINT给主进程,主进程(pcntl_wait)会立刻收到信号并执行信号处理函数”的代码,如有不正确的地方请多多指教:


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);
}

walkor

赞同来自:


最后贴一下描述“在workerman发送信号SIGINT给主进程,主进程(pcntl_wait)会立刻收到信号并执行信号处理函数”的代码,如有不正确的地方请多多指教:



对的

要回复问题请先登录注册