Как прервать выполнение и убить дочерние процессы


Я пытаюсь вызвать длительную команду оболочки внутри скрипта PHP CLI с помощью exec(). Но я ни за что на свете не могу понять, как прервать 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_exec или proc_open)?
  2. После захвата сигнала, как я могу убить любые дочерние процессы, порожденные exec?
Author: hakre, 2012-04-24

1 answers

В документации действительно говорится, что:

Если программа запускается с этой функцией, для того, чтобы она продолжала работать в фоновом режиме, вывод программы должен быть перенаправлен в файл или другой поток вывода. Невыполнение этого требования приведет к зависанию 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, он может отправить SIGINT дочернему процессу с posix_kill($pid, SIGINT).

Обновление: по-видимому, вы также могли бы использовать proc_open и proc_terminate.

 5
Author: Joni, 2014-11-23 04:54:34