Windows 上的子进程未收到信号 (SIGTERM)

niC*_*Mel 4 python windows subprocess signals python-3.x

我有一个启动子send_signal(SIGTERM)进程的服务器,我可以设法执行一个会终止该进程的操作。但并不优雅。如果我从 shell 调用我的子进程(即作为单个进程),则定义的信号处理程序将正常启动并退出。

server.py:(所以..从我第一次调用的另一个脚本start_app(),然后exit_app()

def start_app():
    app = subprocess.Popen("python app.py")

def exit_app():
    p = app.poll()
    if p==None:
        print("Subprocess is alive") # debug
    app.send_signal(signal.SIGTERM)
Run Code Online (Sandbox Code Playgroud)

应用程序

def exit_signal_handler(signal, frame):
    print("Terminate signal received")
    app.exit()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    signal.signal(signal.SIGTERM, exit_signal_handler)
    signal.signal(signal.SIGINT, exit_signal_handler)
    sys.exit(app.exec())
Run Code Online (Sandbox Code Playgroud)

同样,如果我从 shell 调用 app.py 并发送一个SIGTERM信号,我会得到一个跟踪Terminate signal received并关闭应用程序。但是当 app.py 由服务器启动并且我exit_app在服务器中调用时,我得到一个跟踪Subprocess is alive(来自 server.py)并且应用程序被杀死但信号没有被应用程序的信号处理程序捕获exit_signal_handler

编辑:这似乎send_signal()不发送信号,以在该子捕获信号意义上的子进程。它发送信号以在子进程上发生一个动作:

    def send_signal(self, sig):
        """Send a signal to the process
        """
        if sig == signal.SIGTERM:
            self.terminate()
        elif sig == signal.CTRL_C_EVENT:
            os.kill(self.pid, signal.CTRL_C_EVENT)
        elif sig == signal.CTRL_BREAK_EVENT:
            os.kill(self.pid, signal.CTRL_BREAK_EVENT)
        else:
            raise ValueError("Unsupported signal: {}".format(sig))
Run Code Online (Sandbox Code Playgroud)

这可能回答了我的问题,但我会保持开放...

geo*_*xsh 6

当您使用 Windows 时,SIGTERM处理程序是无用的,更多参考

在 Windows 上,C 运行时实现标准 C 所需的六个信号:SIGINT、SIGABRT、SIGTERM、SIGSEGV、SIGILL 和 SIGFPE。

SIGABRT 和 SIGTERM 仅针对当前进程实施。

但您可以使用signal.CTRL_BREAK_EVENT作为替代

即在 app.py 中创建一个处理 的信号处理程序SIGBREAK,但从CTRL_BREAK_EVENT父级发送。另外,请确保使用启动子进程creationflags=subprocess.CREATE_NEW_PROCESS_GROUP(否则它也会杀死父进程)

app = subprocess.Popen("python app.py", shell=True, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
time.sleep(1)

while 1:
    p = app.poll()
    if p is not None:
        break
    app.send_signal(signal.CTRL_BREAK_EVENT)
    time.sleep(2)
Run Code Online (Sandbox Code Playgroud)

应用程序.py:

exit = False

def exit_signal_handler(signal, frame):
    global exit
    print("Terminate signal received")
    exit = True

signal.signal(signal.SIGBREAK, exit_signal_handler)
while not exit:
    pass
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!除了`CTRL_C_EVENT` + `SIGBREAK`,这个`creationflags=subprocess.CREATE_NEW_PROCESS_GROUP` 是**key**,没有它,它也会杀死父进程。 (3认同)