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

时间:2017-11-15 11:57:18

标签: python windows python-3.x subprocess signals

我有一个启动子进程的服务器,我可以设法执行一个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)

app.py

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())

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

这可能回答了我的问题,但我会把它打开......

1 个答案:

答案 0 :(得分:3)

当您使用Windows时,SIGTERM处理程序为useless,更多reference

  

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

     

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

但您可以将signal.CTRL_BREAK_EVENT用作alternative

即。在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)

app.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