写过CLI驻留进程的老司机一定遇到过这样的问题:程序需要更新时,如何安全关闭旧进程?你可能会认为平滑重启如NGINX和php-fpm会向进程发送一个USR2信号,然后它会处理完当前请求再退出。但是进程如何接收和处理信号,估计没有多少人能说清楚。原理实现平滑关机/重启并不难。这里有两个知识点:阻塞信号。当我们的程序在处理一个任务的时候,你肯定不希望它中途终止。例如,如果您正在执行一个数据库事务,您必须不希望事务在提交之前终止。$finish_time){echo"交易完成".PHP_EOL;休息;}}pcntl_signal_dispatch();//分发信号执行上面的代码,5秒内按Ctrl+C,会看到sig_handler被执行了;如果不按Ctrl+C,则不会执行sig_handler。至此你应该明白pcntl_signal()和pcntl_signal_dispatch()的用法了,试试把它放到刚才的代码中};$sig_set=array(SIGINT,SIGTERM);foreach($sig_setas$sig){pcntl_signal($sig,$sig_handler);//注册多个信号}//[1]while(true){//[2-1]pcntl_sigprocmask(SIG_BLOCK,$sig_set);//[2-2]//...//[2-3]pcntl_sigprocmask(SIG_UNBLOCK,$sig_set);//[2-4]}//[3]pcntl_signal_dispatch()应该放在哪里?是[1][2]还是[3]?先试一试,你会发现只有放置[2]才会让信号处理程序执行。同时这个实验也告诉我们,pcntl_signal_dispatch()会导致处理器在信号发生后执行:当放在[1]时,除非你的手速足够快,否则会在你按下Ctrl+C之前执行或杀死通过;并放在[3]中,它将永远没有机会执行。至于放在[2]的什么地方,我建议放在[2-4],因为此时已经处理完任务了。综上所述,您已经了解平滑关机/重启的原理。整理一下上面的半成品代码(因为收到信号后可能会进入下一层循环):
