1、pcntl_signal_dispatch(); 能不能拿到while外面来,这就是一个信号调用函数,我看了源代码,好像里面也是一个循环,去检测信号队列,没有必要while两次
2、再者为什么要调用两次,我去掉了一个,wm也能跑起来
protected static function monitorWorkers()
{
self::$_status = self::STATUS_RUNNING;
while(1)
{
// 如果有信号到来,尝试触发信号处理函数
pcntl_signal_dispatch();
// 挂起进程,直到有子进程退出或者被信号打断
$status = 0;
$pid = pcntl_wait($status, WUNTRACED);
// 如果有信号到来,尝试触发信号处理函数
pcntl_signal_dispatch();
// 有子进程退出
if($pid > 0)
{
// 查找是哪个进程组的,然后再启动新的进程补上
foreach(self::$_pidMap as $worker_id => $worker_pid_array)
{
if(isset($worker_pid_array))
3、主进程和子进程的信号处理,有什么不同,我感觉都是安装信号处理函数,不能公用么
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);
}
/**
* 为子进程重新安装信号处理函数,使用全局事件轮询监听信号
* @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是检查当前进程是否收到信号,如果收到就执行信号处理函数(如果有的话)
1、这是主进程中的代码。pcntl_signal_dispatch不能拿到while外面来,拿到外面那么整个主进程生命周期就检查了一次信号,后面再有信号到来时就无法检查信号并响应,这个问题显而易见。
关于你说的while两次,即使pcntl_signal_dispatch的实现源码中是while循环,也是有退出条件的,不然pcntl_signal_dispatch就永远无法返回,有点服务器编程经验的都不会想永远阻塞在信号检查函数上不返回。
2、为什么while中调用pcntl_signal_dispatch两次。举个例子,一个工人(进程)在睡觉(pcntl_wait),被叫醒说有任务来了(有信号来了),工人开始处理任务包括检查信号(pcntl_signal_dispatch)以及fork进程(有需要的话),执行任务的过程中可能会有新的信号过来,这时工人是不知道的,所以在处理完任务后再次入睡(pcntl_wait)之前,工人需要再次检查(pcntl_signal_dispatch)是否又有新的任务出现。
另外主进程是阻塞在pcntl_wait上的,如果没有信号打断,那么将一直睡眠,不会有任何性能消耗。
也就是只有运行status、reload、restart等命令时才后执行到pcntl_signal_dispatch
3、子进程一般是使用libevent作为事件轮询库,信号处理需要重新注册到libevent中,所以需要把之前信号注册删掉