PHP Conference Japan 2024

pcntl_signal_dispatch

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

pcntl_signal_dispatch调用待处理信号的信号处理程序

描述

pcntl_signal_dispatch(): 布尔型

pcntl_signal_dispatch() 函数调用由 pcntl_signal() 安装的,用于每个待处理信号的信号处理程序。

参数

此函数没有参数。

返回值

成功时返回 true,失败时返回 false

范例

示例 #1 pcntl_signal_dispatch() 例子

<?php
echo "安装信号处理程序...\n";
pcntl_signal(SIGHUP, function($signo) {
echo
"信号处理程序被调用\n";
});

echo
"生成 SIGHUP 信号到自身...\n";
posix_kill(posix_getpid(), SIGHUP);

echo
"分发...\n";
pcntl_signal_dispatch();

echo
"完成\n";

?>

以上示例将输出类似于以下内容

Installing signal handler...
Generating signal SIGHUP to self...
Dispatching...
signal handler called
Done

参见

添加注释

用户贡献的注释 4 条注释

41
webmaster at ajeux dot com
15 年前
如果您以 CLI 方式运行 PHP 并作为“守护进程”(即循环中),则必须在每个循环中调用此函数以检查是否有新的信号等待分发。
9
me at subsonic dot cz
10 年前
请注意,从由之前的 pcntl_signal_dispatch() 调用的信号处理程序中调用 pcntl_signal_dispatch() 将不会触发任何新的待处理信号的处理程序。这意味着,如果您编写一个响应信号分叉子进程的 CLI 守护进程,那么这些子进程将无法响应信号。这让我头疼了一段时间,因为当发生这种情况时,pcntl_signal_dispatch() 不会引发任何错误。一个解决方案是在信号处理程序中设置一个标志,并在父进程的主循环中的其他地方对其做出反应(通过分叉所需的子进程)。
0
stefanis
10 年前
正如“me at subsonic dot net”所指出的那样,从由之前的 pcntl_signal_dispatch() 调用的信号处理程序中调用 pcntl_signal_dispatch() 将不会触发任何新的待处理信号的处理程序。即使您 pcntl_exec() 一个新的 PHP 处理器来执行一个完全不同的脚本,这似乎也是正确的。

解决方案似乎是在 ticks_handler() 内显式调用 pcntl_signal_dispatch()。并将 sig_handler(int) 用作推送到队列的函数。在 ticks_handler 中调用分发之后,立即弹出您的队列,执行您本来会在信号处理程序中执行的操作,直到队列为空。
-2
stefanis
10 年前
好吧,我之前说错了。仅仅在信号处理程序之外处理信号是不够的。它们必须在 tick 处理程序(显式或隐式)之外处理。所以……

注册一个调用 pcntl_signal_dispatch() 的 tick 处理程序;
在信号处理程序中,将您的信号入队;
在脚本的主循环中,处理您的信号;

<?php
declare(ticks=1);
global
$sig_queue;
global
$use_queue;
$sig_queue = array();
$use_queue = true; // 设置为 false 以使用旧方法

function tick_handler()
{
pcntl_signal_dispatch();
}

function
sig_handler($sig)
{
global
$sig_queue;
global
$use_queue;

if(isset(
$use_queue) && $use_queue)
{
$sig_queue[] = $sig;
}
else
{
sig_helper($sig);
}
}

function
sig_helper($sig)
{
switch(
$sig)
{
case
SIGHUP:
$pid = pcntl_fork();
if(
$pid) print("forked $pid\n");
break;

default:
print(
"未处理的信号: $sig\n");
}
}

pcntl_signal(SIGHUP, "sig_handler");

while(
true)
{
if(
$use_queue) foreach($sig_queue as $idx=>$sig)
{
sig_helper($sig);
unset(
$sig_queue[$idx]);
}
sleep(1);
}
?>
To Top