如何中断执行并终止子进程


How to interrupt exec and kill child processes

我正在尝试使用 exec() 在 PHP CLI 脚本中调用一个长时间运行的 shell 命令。但是我一辈子都想不出如何中断PHP脚本并杀死生成的子进程。似乎只要我打电话exec(),我的信号处理程序就会被忽略。以下代码按我预期工作;如果我将 SIGTERM 发送到进程,它会回显SIGTERM并立即退出。

<?php
  declare(ticks = 1);
  function sig_handler($signo) {
    switch ($signo) {
      case SIGTERM:
        echo 'SIGTERM' . PHP_EOL;
        flush();
        break;
      default:
    }
  }
  pcntl_signal(SIGTERM, 'sig_handler', false);
  sleep(60);
?>

但是,如果我将sleep(60);替换为exec('sleep 60');,则在睡眠结束之前,我不会到达我的信号处理程序。我有两个问题:

  1. 如何获取信号以处理exec(或shell_execproc_open)?
  2. 捕获信号后,如何杀死exec生成的子进程?

文档确实说:

如果程序使用此函数启动,为了使它继续在后台运行,必须将程序的输出重定向到文件或其他输出流。否则将导致 PHP 挂起,直到程序执行结束。

(强调我的。我想悬挂也适用于信号处理程序。

为了能够控制子进程,看起来你必须以老式的方式执行它们,使用 fork+exec:

switch ($pid = pcntl_fork()) {
  case -1: // failed to create process
     die('Fork failed');
  case 0: // child
     pcntl_exec($path,$args);
     die('Exec failed');
}

一旦父进程在$pid中拥有子进程 ID,它就可以将 SIGINT 发送给带有 posix_kill($pid, SIGINT) 的子进程。

更新:显然你也可以使用 proc_openproc_terminate .