Python。如何防止子进程接收CTRL-C / Control-C / SIGINT

43 人关注

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

专用服务器必须被明确地给予一个命令来优雅地关闭。因此,CTRL-C必须不能到达服务器进程。

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

So my question is: How to prevent subprocesses from receiving CTRL-C / Control-C / SIGINT?

4 个评论
我对解决方法很感兴趣,如果你把它贴出来就好了!"。
你使用的是什么操作系统?
该专用服务器运行在一个Linux系统(Debian)上。
有谁知道这个问题的解决方案吗? Windows ?
python
subprocess
signals
sigint
keyboardinterrupt
robert
robert
发布于 2011-02-19
5 个回答
robert
robert
发布于 2011-02-19
已采纳
0 人赞同

在#python IRC-Channel (Freenode)中有人帮助我指出了 preexec_fn 的参数 subprocess.Popen(...) :

If preexec_fn 被设置为一个可调用的 对象,这个对象将在 子进程中调用,就在 子进程中调用。(仅限Unix)

Thus, the following code solves the problem (UNIX only):

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

Note:实际上,信号并没有被阻止到达子进程。相反,该preexec_fn上面的方法覆盖了信号的默认处理程序,所以信号被忽略了。因此,这个解决方案可以 not work if the subprocess overwrites the SIGINT处理程序再次。

另一个说明。这个解决方案适用于各种子进程,也就是说,它不限于用Python编写的子进程。例如,我正在为之编写的专用服务器实际上是用Java编写的。

Marek Sapota
Marek Sapota
发布于 2011-02-19
0 人赞同

结合其他一些答案,可以做到这一点--发送到主程序的信号不会被转发给子进程。

import os
from subprocess import Popen
def preexec(): # Don't forward signals.
    os.setpgrp()
Popen('whatever', preexec_fn = preexec)
    
+1 You don't need the preexec function, Popen(args, preexec_nf=os.setpgrp) is cool too.
preexec_nf? Better try Popen(args, preexec_fn=os.setpgrp) ;-)
jpastell
jpastell
发布于 2011-02-19
0 人赞同

你可以像这样做,使其在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)
    
当我使用你的 creationflags 时,主进程在windows上用Ctrl+C是无法杀死的。有什么想法?
@Fuzzyma 我找到了一个快速解决的办法,用 win32api 代替信号。 win32api.SetConsoleCtrlHandler(exit_handler, True) 。工作起来很顺利。
Danil Shaykhutdinov
Danil Shaykhutdinov
发布于 2011-02-19
0 人赞同

经过一个小时的各种尝试,这对我来说是可行的。

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

It's solution for windows.

zwol
zwol
发布于 2011-02-19
0 人赞同