我目前正在为一个在shell中运行的专用服务器编写包装器。该包装器通过subprocess生成服务器进程,并观察和响应其输出。
专用服务器必须明确地给出一个命令以正常关闭。因此,CTRL-C不能到达服务器进程。
如果我在Python中捕获KeyboardInterrupt异常或覆盖SIGINT处理程序,则服务器进程仍会接收CTRL-C并立即停止。
因此我的问题是: 如何防止子进程接收CTRL-C / Control-C / SIGINT信号?
我目前正在为一个在shell中运行的专用服务器编写包装器。该包装器通过subprocess生成服务器进程,并观察和响应其输出。
专用服务器必须明确地给出一个命令以正常关闭。因此,CTRL-C不能到达服务器进程。
如果我在Python中捕获KeyboardInterrupt异常或覆盖SIGINT处理程序,则服务器进程仍会接收CTRL-C并立即停止。
因此我的问题是: 如何防止子进程接收CTRL-C / Control-C / SIGINT信号?
在 #python IRC 频道(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编写的。
Popen(preexec_fn=...)
,最终会导致死锁。我已经遇到过几次这个问题,并且在这里有相关的文档记录:https://docs.python.org/3/library/subprocess.html#subprocess.Popen - Adam CaseyPopen
的process_group
参数:from subprocess import Popen
Popen('do_not_want_signals', process_group=0)
preexec_fn
。import os
from subprocess import Popen
def preexec(): # Don't forward signals.
os.setpgrp()
Popen('do_not_want_signals', preexec_fn=preexec)
# The above can be shortened to:
Popen('do_not_want_signals', preexec_fn=os.setpgrp)
preexec
函数,Popen(args, preexec_fn=os.setpgrp)
也可以。 - Peter SuttonPopen(args, preexec_fn=os.setpgrp)
替代 preexec_nf
。;-) - Marcusprocess_group=0
来替代preexec_fn=os.setpgrp
,因为preexec_fn
与线程不兼容。在早期的Python版本中,可以设置start_new_session=True
来实现类似的结果,而不是使用preexec_fn=
,尽管它的setsid()
调用也会做更多的事情... - gpsimport 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)
creationflags
时,在Windows上无法使用Ctrl+C杀死主进程。有什么想法吗? - Fuzzymawin32api
代替信号:win32api.SetConsoleCtrlHandler(exit_handler, True)
。非常有效。 - Shameer Kashifpreexec_fn=
并使用 3.11 的 process_group=0
或 3.2 的 start_new_session=True
标志,因为 preexec_fn=
不是线程安全的。 - gps经过一个小时的尝试,以下方法对我有效:
process = subprocess.Popen(["someprocess"], creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP)
这是针对Windows的解决方案。