如何中断exec并杀死子进程

时间:2012-04-24 07:09:56

标签: php signals exec pcntl

我正在尝试使用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生成的所有子进程?

1 个答案:

答案 0 :(得分:5)

documentation确实说:

  

如果使用此功能启动程序,为了使其在后台继续运行,必须将程序的输出重定向到文件或其他输出流。 如果不这样做将导致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