我有一个独立的PHP脚本,当发出“kill signal”时,我将处理从Windows OS发送来的信号以进行正常关机。
如何在Windows上执行此操作?
最佳答案
2020年3月更新:自PHP 7.4起,存在sapi_windows_set_ctrl_handler()和sapi_windows_generate_ctrl_event。这使您的脚本可以处理Ctrl + C和Ctrl + Break按键,并为同一进程组中的其他进程生成它们。 proc_open()还添加了create_process_group
选项,以允许子进程处理CTRL事件。就信号处理而言,这是您在Windows上可以做的最好的事情。请注意,这些功能仅对PHP CLI SAPI(即php.exe)可用,并且仅在将进程附加到控制台时才起作用,这在一定程度上限制了它们的实用性。
原始答案:
尽管这里唯一的其他答案是简洁而准确的,但它缺少有关为何Windows不支持信号的详细信息。
首先,信号是与进程进行通信的一种相当有限且过时的方式。有很多更丰富的方法可以通知流程它需要放弃正在执行的操作并执行其他操作。即使在POSIX平台上,信号处理程序也应该非常轻巧-信号处理程序中的代码必须准备就绪/能够处理同时到达的多个信号。
PHP允许通过pcntl_signal()进行信号处理,但有很多警告。在使用它们之前,代码必须先调整传递的“滴答声”的数量,然后PHP才能传递到达处理程序的信号。勾号是Zend(PHP的核心)在检查信号处理程序状态并运行必要的回调之前将执行的指令数。在主执行循环中,这基本上是一个繁忙的循环。因此,如果遵循每笔建议1,调整刻度将大大减慢该过程。该功能的注释表明,在大多数系统上,滴答值为100足够。理解处理程序如何工作的最简单方法是在幕后有一个实际的信号处理程序来收集信号信息,PHP偶尔会查询该信号处理程序以查看是否调用了该处理程序,发送了哪个信号,等等。信息将传递到用户区中的回调(即您的代码)。这不是真正的信号处理,也绝不会由于真正的信号处理所带来的危险和困难而引起。
第二个问题是,即使使用pcntl_signal()提供的伪信号处理程序支持,PHP也会丢失有关发生信号的信息。如果发生多信号情况,则不会通知脚本多次发生了某些信号。滴答值越大,发生这种情况的可能性就越大,尤其是在繁忙的系统上。
Windows在大多数情况下并没有真正使用信号。存在SetConsoleCtrlHandler()函数,该函数可捕获Ctrl + C和Ctrl + Break,并且大致等效于SIGINT。缺点是必须在流程上附加一个控制台,该控制台才能正常工作,并且不能由其他流程发送。 TerminateProcess()函数等效于SIGKILL,该函数在其他OS下不能被阻止/处理,并且SIGKILL信号实际上并未到达目标进程。除了这两个功能/信号外,几乎没有什么共同点。最终,Windows是一个与众不同的野兽。
查看信号的唯一原因是某种形式的长期运行的PHP流程-似乎每个人都说该语言不适合该任务(我完全不同意,但这是不同的讨论)。当我了解甚至在POSIX OS下,PHP中信号支持的局限性时,我认为它们并不是我所遇到的问题的真正答案。正确的解决方案是完全忽略信号。对于SIGINT,应该编写命令行脚本来处理过早终止的情况-也就是说,它们应该是幂等的。在PHP的世界中,信号在很大程度上是无关紧要的,因为还有其他更灵活,更丰富的解决方案,包括命名的互斥体/事件,套接字,文件,命名的管道,共享内存,Service Manager等。
关于php - Windows上的信号处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3333276/