4

我正在编写一个守护进程,它周期性地做一些工作并在再次重复之前休眠一段时间。但它在睡眠时仍必须对外部影响(即终止请求)做出响应。

我设法用 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

同时,如果我不设置这个处理程序,脚本会因为 unhandler 信号而死掉。

我错过了什么吗?为什么我的信号处理函数从未被调用?pcntl_sigwaitinfo() 会干扰吗?

还有其他方法可以同时实现超时和信号处理吗?

4

1 回答 1

4

这并不完全出乎意料。

您已要求将信号传递给信号处理程序 ( pcntl_signal(...)),但随后还要求在不调用任何处理程序 ( ) 的情况下接受信号pcntl_sigwaitinfo(...)。您的操作系统可以决定在这种情况下会发生什么,而您的操作系统(如我的)选择让pcntl_sigwaitinfo()胜利。

背景

进程可以通过两种不同的方式接收(“受苦?”)信号:

  1. 异步传递

    该信号会引发一些异步操作,通常会终止进程或调用用户定义的处理程序。pcntl_signal只注册这样一个处理程序。

    C 程序员熟悉的底层调用是signalsigaction

  2. 同步验收

    特殊的系统函数注意到一个信号处于未决状态,并将其从未决列表中删除,将有关信号的信息返回给进程。 pcntl_sigwaitinfo就是这样一个功能。

    基础调用是sigwait和。sigwaitinfosigtimedwait

这两种方式,交付接受,是不同的,不能一起使用。例如,AIX 简单地禁止“[c]oncurrent use of sigaction and sigwait

(与上面相关的是信号掩码的概念,它可以“阻塞”信号,有效地迫使它们保持挂起直到被接受或直到“解除阻塞”并被传递。)

于 2012-10-11T03:08:05.380 回答