5

根据pcntl_wait的 PHP 文档,

等待函数暂停当前进程的执行,直到一个子进程退出,或者直到一个信号被传递,其动作是终止当前进程或调用一个信号处理函数。

但是,当我运行以下代码并将 SIGTERM 发送到父进程时,仅在子进程退出后才kill -s SIGTERM [pid]调用信号处理程序(即我必须等待睡眠完成。不应该被 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 版本 => 5.3.3

4

2 回答 2

4

您的呼叫pcntl_signal指定应重新启动呼叫。检查文档,默认情况下restart_syscallstrue因此,在孩子终止之前,您的电话pcntl_signal不会返回。

您无需调用flush。所以 PHP 可以将 的输出保存echo在缓冲区中。

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

于 2012-04-24T01:03:36.720 回答
0

pcntl_wait呼叫不能被信号中断,除非restart_syscalls=false孩子死了。

wait系统调用的文档(这是什么pcntl_wait调用):

...它们会阻塞,直到子更改状态或信号处理程序中断调用(假设系统调用不会使用 sigaction(2) 的 SA_RESTART 标志自动重新启动)。

最后一部分非常重要。只有当系统调用没有自动重启时,调用才会被中断(restart_syscalls=false)。

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

sleep() 导致调用线程休眠,直到经过以秒为单位指定的实时秒数,或者直到没有被忽略的信号到达。

TL;博士; pcntl_wait 不能被打断,除非你通过restart_syscalls=false.

于 2020-01-22T15:48:55.053 回答