Python: как запретить подпроцессам получать CTRL-C / Control-C / SIGINT - PullRequest
38 голосов
/ 18 февраля 2011

В настоящее время я работаю над оболочкой для выделенного сервера, работающего в оболочке. Оболочка порождает процесс сервера через подпроцесс, наблюдает и реагирует на его вывод.

Выделенному серверу нужно явно дать команду на корректное завершение работы. Таким образом, CTRL-C не должен достигать процесса сервера.

Если я перехватываю исключение KeyboardInterrupt или перезаписываю обработчик SIGINT в python, процесс сервера все равно получает CTRL-C и немедленно останавливается.

Итак, мой вопрос: Как предотвратить получение подпроцессов CTRL-C / Control-C / SIGINT?

Ответы [ 4 ]

37 голосов
/ 19 февраля 2011

Кто-то из IRC-канала #python (Freenode) помог мне, указав preexec_fn параметр subprocess.Popen (...) :

Если preexec_fn установлено в вызываемый объект, этот объект будет вызываться в дочернем процессе непосредственно перед выполнением дочернего процесса.(Только для Unix)

Таким образом, следующий код решает проблему (только для UNIX):

import subprocess
import signal

def preexec_function():
    # Ignore the SIGINT signal by setting the handler to the standard
    # signal handler SIG_IGN.
    signal.signal(signal.SIGINT, signal.SIG_IGN)

my_process = subprocess.Popen(
    ["my_executable"],
    preexec_fn = preexec_function
)

Примечание: Сигнал фактически не предотвращаетсядостигнув подпроцесса.Вместо этого preexec_fn выше перезаписывает обработчик сигнала по умолчанию, так что сигнал игнорируется.Таким образом, это решение может не работать, если подпроцесс снова перезаписывает обработчик SIGINT .

Еще одно примечание: Это решение работает для всех видовподпроцессы, то есть он не ограничивается подпроцессами, написанными также на Python.Например, выделенный сервер, для которого я пишу свою оболочку, фактически написан на Java.

23 голосов
/ 27 марта 2011

Объединение некоторых других ответов, которые помогут, - сигнал, отправленный основному приложению, не будет перенаправлен в подпроцесс.

import os
from subprocess import Popen

def preexec(): # Don't forward signals.
    os.setpgrp()

Popen('whatever', preexec_fn = preexec)
2 голосов
/ 27 августа 2016

вы можете сделать что-то подобное, чтобы заставить его работать в Windows и Unix:

import subprocess
import sys

def pre_exec():
    # To ignore CTRL+C signal in the new process
    signal.signal(signal.SIGINT, signal.SIG_IGN)

if sys.platform.startswith('win'):
    #https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
    #CREATE_NEW_PROCESS_GROUP=0x00000200 -> If this flag is specified, CTRL+C signals will be disabled
    my_sub_process=subprocess.Popen(["executable"], creationflags=0x00000200)
else:
    my_sub_process=subprocess.Popen(["executable"], preexec_fn = pre_exec)
1 голос
/ 18 февраля 2011

Попробуйте установить для SIGINT значение , игнорируемое , перед тем как запускать подпроцесс (впоследствии сбросьте его на поведение по умолчанию).

Если это не сработает, вам нужно прочитать управление заданиями и узнать, как поместить процесс в собственную группу фоновых процессов, чтобы ^ C даже не заставляло ядро ​​отправлять ему сигнал в первую очередь.(Может быть невозможным в Python без написания помощников на языке C.)

См. Также этот старый вопрос .

...