我看pcntl源碼中php_pcntl_pending_signal先初始化為32個(gè),丟失信號(hào)的場(chǎng)景就是信號(hào)隊(duì)列滿了吧,代碼如下:
psig = PCNTL_G(spares);
if (!psig) {
/ oops, too many signals for us to track, so we'll forget about this one /
return;
}
如果隊(duì)列沒(méi)滿的話是可以繼續(xù)處理的,如果滿了,來(lái)的信號(hào)都丟了,第二次的pcntl_signal_dispatch 是預(yù)防那些場(chǎng)景那?相關(guān)php代碼如圖片所示
pcntl_signal_dispatch()
是處理已經(jīng)收到的信號(hào)。
假設(shè)只有一個(gè)pcntl_signal_dispatch()
,
截圖里代碼簡(jiǎn)化成如下
while (1){
pcntl_signal_dispatch(); // 位置1
$pid= pcntl_wait(); // 位置2
}
正常情況下,進(jìn)程是阻塞在位置2。
當(dāng)信號(hào)到來(lái)時(shí),pcntl_wait()返回,代碼繼續(xù)執(zhí)行,就執(zhí)行到了位置1。
執(zhí)行1程中,這時(shí)候有新的信號(hào)到來(lái),新的信號(hào)放入信號(hào)隊(duì)列不做處理(因?yàn)樾枰俅握{(diào)用pcntl_signal_dispatch()
才能被處理)。
執(zhí)行完1后代碼繼續(xù)執(zhí)行2,然后一直阻塞在2的位置,新來(lái)的信號(hào)沒(méi)有被處理(這里其實(shí)意思是沒(méi)被處理,信號(hào)其實(shí)沒(méi)丟)。
所以在workerman里又調(diào)用了一次pcntl_signal_dispatch()
,這樣能夠盡量避免漏掉信號(hào)。
以下是丟失信號(hào)的一個(gè)demo,你可以自己測(cè)試下。
test.php
<?php
echo "pid=".posix_getpid()."\n";
pcntl_signal(SIGUSR1, function(){
echo "GET SIGNAL\n";
posix_kill(posix_getpid(), SIGUSR1); // 這里模擬在處理信號(hào)的過(guò)程中收到新的信號(hào)
}, false);
while (1) {
pcntl_signal_dispatch();
sleep(10000);
//pcntl_signal_dispatch();
}
運(yùn)行 php test.php,然后在另外一個(gè)終端上給這個(gè)進(jìn)程發(fā)送信號(hào) kill -SIGUSR1 pid
,如果只有一個(gè) pcntl_signal_dispatch();
,你會(huì)看到只打印一個(gè) GET SIGNAL
。但是實(shí)際上代碼執(zhí)行過(guò)程中一共收到了2個(gè)信號(hào)。
有一個(gè)信號(hào)看起來(lái)丟失了。
@walkor:就像你說(shuō)的兩個(gè)也是盡量避免漏掉,如果在執(zhí)行第二個(gè)的時(shí)候又來(lái)了個(gè)信號(hào),但是執(zhí)行完之后會(huì)退出循環(huán),一樣會(huì)有信號(hào)漏掉,當(dāng)然這是極端的情況。我說(shuō)的那種情況就像Events/select中的loop一樣(當(dāng)然也有可能漏掉),就像如下代碼: