我正在写一个守护进程,它会在一段时间内完成一些工作,并在再次重复之前休息一段时间。但它必须在睡着时对外部影响(即终止请求)作出反应。
我设法用ALRM信号实现睡眠超时,并用TERM信号(样本)终止:
// ...
declare(ticks = 1);
function do_work()
{
echo "Doing some work.\n";
}
$term = FALSE;
$sighandler = function ($signal) use (&$term)
{
if ($signal === SIGTERM)
{
pcntl_alarm(0);
$term = TRUE;
echo "TERM HANDLER\n";
} else {
echo "ALRM HANDLER\n";
}
};
pcntl_signal(SIGALRM, $sighandler);
pcntl_signal(SIGTERM, $sighandler);
while (!$term)
{
do_work();
// Kick myself after 2 seconds
pcntl_alarm(2);
// Wait for alarm or termination
$signal = pcntl_sigwaitinfo(array(SIGTERM, SIGALRM), $info);
pcntl_signal_dispatch();
switch ($signal)
{
case SIGALRM: echo "ALRM SIGWI\n"; break;
case SIGTERM: echo "TERM SIGWI\n"; $term = TRUE; break;
}
}
// ...
但是为了上帝的缘故,我无法弄清楚为什么sighandler永远不会被召唤。我得到以下输出:
$ php sigsample.php
Doing some work.
ALRM SIGWI
Doing some work.
ALRM SIGWI
Doing some work.
TERM SIGWI
同时如果我没有设置这个处理程序,脚本会因为信号不正确而死掉。
我是否错过了一些人?为什么我的信号处理函数从未调用过?它是pcntl_sigwaitinfo()干扰吗?
还有其他方法可以同时实现超时和信号处理吗?
答案 0 :(得分:3)
这并非完全出乎意料。
您已要求传递给信号处理程序(pcntl_signal(...)
),但之后还要求接受该信号而不调用任何处理程序(pcntl_sigwaitinfo(...)
)。您的操作系统可以决定在这种情况下会发生什么,您的操作系统(如我的)选择让pcntl_sigwaitinfo()
获胜。
进程可以通过两种不同的方式接收(“遭受?”)信号:
该信号会引发一些异步操作,通常会终止进程或调用用户定义的处理程序。 pcntl_signal
只注册这样一个处理程序。
特殊系统功能会注意信号处于待处理状态,并将其从待处理列表中删除,并将有关信号的信息返回给进程。 pcntl_sigwaitinfo
就是这样一个功能。
基础来电是sigwait
,sigwaitinfo
和sigtimedwait
。
这两种方式,交付和接受,different和并不意味着一起使用。例如,AIX只是禁止"[c]oncurrent use of sigaction and sigwait"。
(与上述相关的是信号掩码的概念,它可以“阻止”信号,有效地迫使它们保持待决状态直到被接受或直到“解除阻塞”并被传递。)