我看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;
}
如果隊列沒滿的話是可以繼續(xù)處理的,如果滿了,來的信號都丟了,第二次的pcntl_signal_dispatch 是預(yù)防那些場景那?相關(guān)php代碼如圖片所示
pcntl_signal_dispatch()
是處理已經(jīng)收到的信號。
假設(shè)只有一個pcntl_signal_dispatch()
,
截圖里代碼簡化成如下
while (1){
pcntl_signal_dispatch(); // 位置1
$pid= pcntl_wait(); // 位置2
}
正常情況下,進(jìn)程是阻塞在位置2。
當(dāng)信號到來時,pcntl_wait()返回,代碼繼續(xù)執(zhí)行,就執(zhí)行到了位置1。
執(zhí)行1程中,這時候有新的信號到來,新的信號放入信號隊列不做處理(因為需要再次調(diào)用pcntl_signal_dispatch()
才能被處理)。
執(zhí)行完1后代碼繼續(xù)執(zhí)行2,然后一直阻塞在2的位置,新來的信號沒有被處理(這里其實意思是沒被處理,信號其實沒丟)。
所以在workerman里又調(diào)用了一次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,然后在另外一個終端上給這個進(jìn)程發(fā)送信號 kill -SIGUSR1 pid
,如果只有一個 pcntl_signal_dispatch();
,你會看到只打印一個 GET SIGNAL
。但是實際上代碼執(zhí)行過程中一共收到了2個信號。
有一個信號看起來丟失了。