Подтвердить что ты не робот

Python: как предотвратить подпроцессы от приема CTRL-C/Control-C/SIGINT

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

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

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

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

4b9b3361

Ответ 1

Кто-то из #python IRC-канала (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.

Ответ 2

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

import os
from subprocess import Popen

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

Popen('whatever', preexec_fn = preexec)

Ответ 3

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

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

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

Ответ 4

вы можете сделать что-то подобное, чтобы заставить его работать в 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)