1、pcntl_signal_dispatch(); 能不能拿到while外面來(lái),這就是一個(gè)信號(hào)調(diào)用函數(shù),我看了源代碼,好像里面也是一個(gè)循環(huán),去檢測(cè)信號(hào)隊(duì)列,沒(méi)有必要while兩次
2、再者為什么要調(diào)用兩次,我去掉了一個(gè),wm也能跑起來(lái)
protected static function monitorWorkers()
{
self::$_status = self::STATUS_RUNNING;
while(1)
{
// 如果有信號(hào)到來(lái),嘗試觸發(fā)信號(hào)處理函數(shù)
pcntl_signal_dispatch();
// 掛起進(jìn)程,直到有子進(jìn)程退出或者被信號(hào)打斷
$status = 0;
$pid = pcntl_wait($status, WUNTRACED);
// 如果有信號(hào)到來(lái),嘗試觸發(fā)信號(hào)處理函數(shù)
pcntl_signal_dispatch();
// 有子進(jìn)程退出
if($pid > 0)
{
// 查找是哪個(gè)進(jìn)程組的,然后再啟動(dòng)新的進(jìn)程補(bǔ)上
foreach(self::$_pidMap as $worker_id => $worker_pid_array)
{
if(isset($worker_pid_array))
3、主進(jìn)程和子進(jìn)程的信號(hào)處理,有什么不同,我感覺(jué)都是安裝信號(hào)處理函數(shù),不能公用么
protected static function installSignal()
{
// stop
pcntl_signal(SIGINT, array('\Workerman\Worker', 'signalHandler'), false);
// reload
pcntl_signal(SIGUSR1, array('\Workerman\Worker', 'signalHandler'), false);
// status
pcntl_signal(SIGUSR2, array('\Workerman\Worker', 'signalHandler'), false);
// ignore
pcntl_signal(SIGPIPE, SIG_IGN, false);
}
/**
* 為子進(jìn)程重新安裝信號(hào)處理函數(shù),使用全局事件輪詢監(jiān)聽(tīng)信號(hào)
* @return void
*/
protected static function reinstallSignal()
{
// uninstall stop signal handler
pcntl_signal(SIGINT, SIG_IGN, false);
// uninstall reload signal handler
pcntl_signal(SIGUSR1, SIG_IGN, false);
// uninstall status signal handler
pcntl_signal(SIGUSR2, SIG_IGN, false);
// reinstall stop signal handler
self::$globalEvent->add(SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler'));
// uninstall reload signal handler
self::$globalEvent->add(SIGUSR1, EventInterface::EV_SIGNAL,array('\Workerman\Worker', 'signalHandler'));
// uninstall status signal handler
self::$globalEvent->add(SIGUSR2, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler'));
}
pcntl_signal_dispatch是檢查當(dāng)前進(jìn)程是否收到信號(hào),如果收到就執(zhí)行信號(hào)處理函數(shù)(如果有的話)
1、這是主進(jìn)程中的代碼。pcntl_signal_dispatch不能拿到while外面來(lái),拿到外面那么整個(gè)主進(jìn)程生命周期就檢查了一次信號(hào),后面再有信號(hào)到來(lái)時(shí)就無(wú)法檢查信號(hào)并響應(yīng),這個(gè)問(wèn)題顯而易見(jiàn)。
關(guān)于你說(shuō)的while兩次,即使pcntl_signal_dispatch的實(shí)現(xiàn)源碼中是while循環(huán),也是有退出條件的,不然pcntl_signal_dispatch就永遠(yuǎn)無(wú)法返回,有點(diǎn)服務(wù)器編程經(jīng)驗(yàn)的都不會(huì)想永遠(yuǎn)阻塞在信號(hào)檢查函數(shù)上不返回。
2、為什么while中調(diào)用pcntl_signal_dispatch兩次。舉個(gè)例子,一個(gè)工人(進(jìn)程)在睡覺(jué)(pcntl_wait),被叫醒說(shuō)有任務(wù)來(lái)了(有信號(hào)來(lái)了),工人開(kāi)始處理任務(wù)包括檢查信號(hào)(pcntl_signal_dispatch)以及fork進(jìn)程(有需要的話),執(zhí)行任務(wù)的過(guò)程中可能會(huì)有新的信號(hào)過(guò)來(lái),這時(shí)工人是不知道的,所以在處理完任務(wù)后再次入睡(pcntl_wait)之前,工人需要再次檢查(pcntl_signal_dispatch)是否又有新的任務(wù)出現(xiàn)。
另外主進(jìn)程是阻塞在pcntl_wait上的,如果沒(méi)有信號(hào)打斷,那么將一直睡眠,不會(huì)有任何性能消耗。
也就是只有運(yùn)行status、reload、restart等命令時(shí)才后執(zhí)行到pcntl_signal_dispatch
3、子進(jìn)程一般是使用libevent作為事件輪詢庫(kù),信號(hào)處理需要重新注冊(cè)到libevent中,所以需要把之前信號(hào)注冊(cè)刪掉