Signal (SIGTERM) not received by subprocess on Win

2019-02-26 09:19发布

I have a server that starts a subprocess, and I can manage to do a send_signal(SIGTERM) which will kill the process. But not gracefully. If I call my subprocess from shell (i.e. as a single process), the defined signal handler will kick in and exit gracefully.

server.py: (so.. from another script I first call start_app(), and later 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())

Again, if I call app.py from shell and send a SIGTERMsignal I get a trace Terminate signal received and app closes. But when app.py is started by server and I call exit_app in server, I get a trace Subprocess is alive (from server.py) and app is killed but the signal is not caught in app's signalhandler exit_signal_handler

EDIT: It seems send_signal() doesn't send a signal to the subprocess in the sense that subprocess catches the signal. It send`s a signal for an action to take place on the subprocess:

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

This probably answers my question but I'll leave it open...

1条回答
霸刀☆藐视天下
2楼-- · 2019-02-26 09:34

As you are using Windows, SIGTERM handler is useless, more reference:

On Windows, the C runtime implements the six signals that are required by standard C: SIGINT, SIGABRT, SIGTERM, SIGSEGV, SIGILL, and SIGFPE.

SIGABRT and SIGTERM are implemented just for the current process.

But you could use signal.CTRL_BREAK_EVENT as an alternative.

I.e. create a signal handler in app.py that handles SIGBREAK, but send the CTRL_BREAK_EVENT from the parent. Also, make sure to start your subprocess using creationflags=subprocess.CREATE_NEW_PROCESS_GROUP (otherwise it will kill the parent as well)

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
查看更多
登录 后发表回答