Надежно завершающий подпроцесс на Python 2.5 - PullRequest
1 голос
/ 31 октября 2011

У меня есть скрипт, который многократно запускает файл сборки Ant и выводит выходные данные в формат для анализа. Когда я создаю подпроцесс с помощью Popen, появляется небольшое временное окно, в котором нажатие Ctrl + C убивает скрипт, но не убивает подпроцесс, выполняющий Ant, оставляя зомби, который печатает вывод на консоль, который может быть уничтожен только с помощью Task. Менеджер. Как только Ant начнет печатать вывод, нажатие Ctrl + C всегда убивает мой скрипт, а также Ant. Есть ли способ сделать так, чтобы нажатие Ctrl + C всегда убивало подпроцесс, выполняющий Ant, не оставляя зомби позади?

Также примечание: у меня есть обработчик для SIGINT, который выполняет несколько операций очистки перед вызовом exit (0). Если я вручную уничтожу подпроцесс в обработчике, используя os.kill(p.pid, signal.SIGTERM) (не SIGINT), тогда я смогу успешно уничтожить подпроцесс в ситуациях, когда он обычно зомбируется. Однако, когда вы нажимаете Ctrl + C, когда Ant начинает выводить данные, вы получаете трассировку стека из подпроцесса, где он не может уничтожить сам подпроцесс, как я его уже уничтожил.


РЕДАКТИРОВАТЬ: Мой код выглядел примерно так:

p = Popen('ls')
def handle_sig_int(signum, stack_frame):
    # perform cleanup
    os.kill(p.pid, signal.SIGTERM)
    exit(0)
signal.signal(signal.SIGINT, handle_sig_int)

p.wait()

Который будет производить следующую трассировку стека при неправильном запуске:

File "****.py", line ***, in run_test
  p.wait()
File "/usr/lib/python2.5/subprocess.py", line 1122, in wait
  pid, sts = os.waitpid(self.pid, 0)
File "****.py", line ***, in handle_sig_int
  os.kill(p.pid, signal.SIGTERM)

Я исправил это, поймав OSError, вызванную p.wait и выйдя:

try:
    p.wait()
except OSError:
    exit('The operation was interrupted by the user')

Кажется, это работает в подавляющем большинстве моих тестовых прогонов. Иногда я получаю uname: write error: Broken pipe, хотя я не знаю, что его вызывает. Кажется, это происходит, если я нажимаю Ctrl + C как раз перед тем, как дочерний процесс может начать отображать вывод.

1 Ответ

2 голосов
/ 31 октября 2011

Вызовите p.terminate() в вашем обработчике SIGTERM:

 if p.poll() is None: # Child still around?
     p.terminate() # kill it

[EDIT] Поскольку вы застряли в Python 2.5, используйте os.kill(p.pid, signal.SIGTERM) вместо p.terminate().Проверка должна гарантировать, что вы не получите исключение (или не уменьшите количество раз, которое вы получите).

Чтобы сделать его еще лучше, вы можете перехватить исключение и проверить сообщение.Если это означает «дочерний процесс не найден», тогда игнорируйте исключение.В противном случае, сбросьте его с raise (без аргументов).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...