44

我目前正在为在 shell 中运行的专用服务器开发一个包装器。包装器通过子进程生成服务器进程,并观察其输出并对其做出反应。

必须明确地给专用服务器一个命令以正常关闭。因此,CTRL-C 不能到达服务器进程。

如果我在 python 中捕获 KeyboardInterrupt 异常或覆盖 SIGINT 处理程序,服务器进程仍会收到 CTRL-C 并立即停止。

所以我的问题是:如何防止子进程接收 CTRL-C / Control-C / SIGINT?

4

5 回答 5

44

#python IRC-Channel(Freenode)中的某个人通过指出subprocess.Popen (...)的preexec_fn参数来帮助我:

如果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 编写的。

于 2011-02-19T11:27:36.553 回答
26

结合其他一些可以解决问题的答案 - 发送到主应用程序的任何信号都不会转发到子进程。

import os
from subprocess import Popen

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

Popen('whatever', preexec_fn = preexec)
于 2011-03-27T03:16:56.513 回答
6

您可以执行以下操作以使其在 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)
于 2016-08-26T21:02:19.500 回答
1

尝试在生成子进程之前将 SIGINT 设置为忽略(之后将其重置为默认行为)。

如果这不起作用,您将需要阅读作业控制并学习如何将进程放在自己的后台进程组中,这样^C甚至不会导致内核首先向它发送信号. (如果不编写 C 助手,在 Python 中可能是不可能的。)

另请参阅这个较旧的问题

于 2011-02-18T20:06:19.310 回答
1

经过一个小时的各种尝试,这对我有用:

process = subprocess.Popen(["someprocess"], creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP)

这是windows的解决方案。

于 2020-08-01T17:59:07.563 回答