原地址:https://www.cnblogs.com/linzhenjie/p/5485436.html
PHP的pcntl扩展提供了信号处理的功能,利用它可以让PHP来接管信号的处理,在开发服务器端守护进程方面,信号处理至关重要。
函数原型
bool pcntl_signal(int $signo ,callback $handler [,bool $restart_syscalls=true])
第一个参数是信号ID
第二个参数是信号发生时回调的PHP函数。
第三个参数是是否restart,是否重新注册此信号。这个参数如果为false,那此信号只注册处理一次。
pcntl_signal的实现
<?php //信号处理需要注册ticks才能生效,这里务必注意 //PHP5.4以上版本就不再依赖ticks了 declare(ticks = 1); function sig_handler($signo){ switch ($signo) { case SIGUSR1: echo "SIGUSR1\n"; break; case SIGUSR2: echo "SIGUSR2\n"; break; default: echo "unknow"; break; } } //安装信号触发器器 pcntl_signal(SIGUSR1, "sig_handler"); pcntl_signal(SIGUSR2, "sig_handler"); //向当前进程发送SIGUSR1信号 posix_kill(posix_getpid(), SIGUSR1); posix_kill(posix_getpid(), SIGUSR2); ?>
执行此代码会在终端输出你想要的结果,其实官方的pcntl_signal性能极差,主要是PHP的函数无法直接注册到操作系统信号设置中,所以pcntl信号需要依赖tick机制来完成。
pcntl_signal的实现原理是,触发信号后先将信号加入一个队列中。然后在PHP的ticks回调函数中不断检查是否有信号,如果有信号就执行PHP中指定的回调函数,如果没有则跳出函数。
ticks=1表示每执行1行PHP代码就回调此函数。实际上大部分时间都没有信号产生,但ticks的函数一直会执行。
比较好的做法是去掉ticks,转而使用pcntl_signal_dispatch,在代码循环中自行处理信号。
pcntl_signal_dispatch的实现
<?php // 定义一个处理器,接收到SIGINT信号后只输出一行信息 function signalHandler($signo) { switch ($signo) { case SIGUSR1: echo "SIGUSR1\n"; break; case SIGUSR2: echo "SIGUSR2\n"; break; default: echo "unknow"; break; } } //安装信号触发器器 pcntl_signal(SIGINT, 'signalHandler'); while (true) { sleep(1); posix_kill(posix_getpid(), SIGUSR1); pcntl_signal_dispatch(); //接收到信号时,调用注册的signalHandler() }
实战:用信号来处理函数超时
<?php function a(){ sleep(10); echo "OK\n"; } function b(){ echo "Stop\n"; } function c(){ usleep(100000); } //信号处理代码 function sig(){ throw new Exception; } try{ pcntl_alarm(2); //设定超时后触发的信号 pcntl_signal(SIGALRM, "sig"); pcntl_signal_dispatch(); a(); pcntl_alarm(0); }catch(Exception $e){ echo "timeout\n"; } b(); a(); //等待十秒后完成 b();