PHP进程间通信的另外一个手段就是通过信号来在进程间传递信息。信号是一种系统调用,通常我们用的kill命令就是发送某个信号给某个进程的。
在开发服务器端守护进程方面,信号处理至关重要。PHP的pcntl扩展提供了信号处理的功能,利用它可以让PHP来接管信号的处理。
今天,我们就来给大家讲一讲PHP中的信号处理。
什么是信号?
信号是事件发生时对进程的通知机制,有时又称为软件中断。一个进程可以向另一个进程发送信号,比如子进程结束时都会向父进程发送一个SIGCHLD(17号信号)来通知父进程,所以有时信号也被当作一种进程间通信的机制。
信号的产生是有多种方式的,下面是常见的几种:
●键盘上按某些组合键,比如Ctrl+C或者Ctrl+D等,会产生SIGINT信号。
●使用posix kill调用,可以向某个进程发送指定的信号。
●远程ssh终端情况下,如果你在服务器上执行了一个阻塞的脚本,正在阻塞过程中你关闭了终端,可能就会产生SIGHUP信号。
●硬件也会产生信号,比如OOM了或者遇到除0这种情况,硬件也会向进程发送特定信号。
而进程在收到信号后,可以有如下三种响应:
●直接忽略,不做任何反映。就是俗称的完全不鸟。但是有两种信号,永远不会被忽略,一个是SIGSTOP,另一个是SIGKILL,因为这两个进程提供了向内核最后的可靠的结束进程的办法。
●捕捉信号并作出相应的一些反应,具体响应什么可以由用户自己通过程序自定义。
●系统默认响应。大多数进程在遇到信号后,如果用户也没有自定义响应,那么就会采取系统默认响应,大多数的系统默认响应就是终止进程。
PHP信号处理案例
我们在FPM模式下写代码,不会遇到信号处理相关的问题,但是CLI模式下一些常驻内存的脚本,如何能够自由的重启、关闭、退出前做一些清理工作(断开链接,删除临时文件等)?
pcntl_signal是PHP的信号处理注册方法,这个是pcntl初始化的时候,将pcntl_signal_dispatch注册为tick的处理函数。
pcntl_signal会将处理函数放到信号集合中(PHP的hash table),而php_signale4最终会调用sigaction进行底层的信号管理。
这里我省略了大量代码,将关键的点标记了出来,其实PHP维护一个自己的信号集合,每当调用 pcntl_signal_dispatch时就会查询是否有信号,上面的SIG_BLOCK会将信号阻塞,这样只有我们把关键的代码执行完毕之后,再去触发信号处理函数以保证数据和程序逻辑的完整性。
经常见到身边的程序员们,每当需要重启PHP-FPM进程的时候,使用的招数是kill掉所有PHP进程,然后新启动。一般情况没啥问题,但有些时候可能某个进程的任务还没执行完,直接把人家中断了略显粗暴。
其实只要你给PHP的Master进程发送一条USR2信号,它便会再处理完所有任务后,重启子进程,这才是所谓的优雅。
以上图为例,如果我们想让进程优雅退出的时候,只需要发送SIGTERM信号即可。需要注意的是SIGKILL和SIGSTOP信号会略过信号阻塞会将进程直接停止,还有就是信号会中断睡眠(SLEEP),sleep如果没执行完会返回剩下的秒数。
信号相关的知识点其实有很多,还需要大家在平时的使用中继续深入研究。以上就是这篇文章的全部内容,希望能对大家有所帮助。