关于执行两次pcntl_signal_dispatch的问题,烦请解惑

0

我看pcntl源码中php_pcntl_pending_signal先初始化为32个,丢失信号的场景就是信号队列满了吧,代码如下:
psig = PCNTL_G(spares);
if (!psig) {
/ oops, too many signals for us to track, so we'll forget about this one /
return;
}


如果队列没满的话是可以继续处理的,如果满了,来的信号都丢了,第二次的pcntl_signal_dispatch 是预防那些场景那?相关php代码如图片所示

pcntl_signal_dispatch.png
已邀请:

walkor

赞同来自:

pcntl_signal_dispatch()是处理已经收到的信号。


假设只有一个pcntl_signal_dispatch()
截图里代码简化成如下


while (1){
pcntl_signal_dispatch(); // 位置1
$pid= pcntl_wait(); // 位置2
}

正常情况下,进程是阻塞在位置2。
当信号到来时,pcntl_wait()返回,代码继续执行,就执行到了位置1。
执行1程中,这时候有新的信号到来,新的信号放入信号队列不做处理(因为需要再次调用pcntl_signal_dispatch()才能被处理)。
执行完1后代码继续执行2,然后一直阻塞在2的位置,新来的信号没有被处理(这里其实意思是没被处理,信号其实没丢)。


所以在workerman里又调用了一次pcntl_signal_dispatch(),这样能够尽量避免漏掉信号。


以下是丢失信号的一个demo,你可以自己测试下。
test.php


<?php
echo "pid=".posix_getpid()."\n";
pcntl_signal(SIGUSR1, function(){
echo "GET SIGNAL\n";
posix_kill(posix_getpid(), SIGUSR1); // 这里模拟在处理信号的过程中收到新的信号
}, false);

while (1) {
pcntl_signal_dispatch();
sleep(10000);
//pcntl_signal_dispatch();
}

运行 php test.php,然后在另外一个终端上给这个进程发送信号 kill -SIGUSR1 pid,如果只有一个 pcntl_signal_dispatch();,你会看到只打印一个 GET SIGNAL。但是实际上代码执行过程中一共收到了2个信号。
有一个信号看起来丢失了。

andyc

赞同来自:

@walkor:就像你说的两个也是尽量避免漏掉,如果在执行第二个的时候又来了个信号,但是执行完之后会退出循环,一样会有信号漏掉,当然这是极端的情况。我说的那种情况就像Events/select中的loop一样(当然也有可能漏掉),就像如下代码:
截图

要回复问题请先登录注册