pcntl_wait没有被SIGTERM中断

时间:2012-04-24 00:52:42

标签: php sigterm pcntl

根据pcntl_wait的PHP文档,

  

wait函数暂停当前进程的执行,直到子进程退出,或者直到发出信号,其动作是终止当前进程或调用信号处理函数。

但是,当我运行以下代码并使用kill -s SIGTERM [pid]将SIGTERM发送到父进程时,信号处理程序仅在子进程后被称为(即我必须等待睡眠完成.SIGTERM不应该pcntl_wait()中断吗?

fork_test.php:

<?php
  declare(ticks = 1);

  function sig_handler($signo) {
    switch ($signo) {
      case SIGTERM:
        echo 'SIGTERM' . PHP_EOL;
        break;
      default:
    }
  }

  pcntl_signal(SIGTERM, 'sig_handler');

  $pid = pcntl_fork();

  if ($pid == -1) {
     die('could not fork');
  }
  else if ($pid) {
    echo 'parent' . PHP_EOL;

    pcntl_wait($status);
  }
  else {
    echo 'child' . PHP_EOL;
    sleep(30);
  }
?>

输出(SIGTERM仅在等待30秒后出现):

$ php fork_test.php
child
parent
SIGTERM

PHP Version =&gt; 5.3.3

2 个答案:

答案 0 :(得分:3)

您对pcntl_signal的呼叫指定应重新启动呼叫。默认情况下,请检查docsrestart_syscallstrue。因此,在孩子被终止之前,您对pcntl_signal的呼叫不会返回。

您没有致电flush。因此,PHP可以将echo的输出保存在缓冲区中。

因此,您所看到的行为正是您要求的行为。重新启动系统调用并缓冲输出。

答案 1 :(得分:0)

bool a; a = 25;的呼叫不能被信号打断,除非pcntl_wait或孩子死亡。

摘自restart_syscalls=false syscall(wait调用)的文档:

...它们阻塞,直到有一个孩子变了 状态或信号处理程序中断了调用(假设该系统 使用的SA_RESTART标志不会自动重新启动呼叫 sigaction(2))。

最后一部分非常重要。仅当系统调用没有自动重新启动(pcntl_wait)时,呼叫才会中断。

有趣的是,当进程接收到信号时,并非所有系统调用的行为都相同。例如,restart_syscalls=false syscall将等待秒数或等待任何信号后再继续。即使您通过sleepsleep也不会在中断的地方重新启动。从restart_syscalls=true手册中:

sleep()使调用线程进入睡眠状态,直到 以秒为单位指定的实时秒已过去或直到信号 到达,将被忽略。

TL; DR;除非您通过sleep,否则pcntl_wait不会被中断。