【问题标题】:Signal (SIGTERM) not received by subprocess on WindowsWindows 上的子进程未收到信号 (SIGTERM)
【发布时间】:2018-04-28 15:25:13
【问题描述】:

我有一个启动子进程的服务器,我可以设法执行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 并发送 SIGTERMsignal 我会得到跟踪 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))

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

【问题讨论】:

  • @georgexsh kill = 完成,退出,进程不再在 CPU 上运行。并且 poll() 只是作为一个健全性检查,以在发送 SIGTERM 之前查看子进程实际上是活动的
  • 所以真正的问题是您还没有看到应该打印信号处理程序的消息?尝试写入文件?
  • @georgexsh 嗯...好点。我知道你打算用这个去哪里,但是当以subprocess() 运行时,__main__ 中发生的事情会被打印出来。我也有print(),但这里没有包含它。
  • 您可以通过将日志写入文件来确认这一点,并检查app.poll()的返回值是0还是-15,0表示正常退出并且信号处理程序工作。
  • 在您的新编辑中,您使用的是 windows 吗?

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


【解决方案1】:

当您使用 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

【讨论】:

  • 也许我一直不清楚,可能会编辑问题。在这两种情况下,应用程序都由SIGTERM 终止,但是当作为子进程运行时,app.py 中的信号处理程序不会被调用...应用程序会立即终止
  • 不错的参考资料。问题是,如果我注册 SIGINT 并在键盘上按 ctrl+c,我的处理程序会捕获信号...但是当作为子进程运行时,我无法从脚本发送信号,因为 send_signal(signal.SIGINT) 会引发错误(如在我的编辑中看到)。这一切都很奇怪
  • 你为什么使用SIGINT
  • Aahhh...你注册SIGBREAK但发送CTRL_BREAK_EVENT
  • 谢谢!除了CTRL_C_EVENT + SIGBREAK,这个creationflags=subprocess.CREATE_NEW_PROCESS_GROUPkey,没有它,它也会杀死父母。
猜你喜欢
  • 2013-06-05
  • 1970-01-01
  • 1970-01-01
  • 2017-08-22
  • 1970-01-01
  • 2020-01-12
  • 2016-07-18
  • 2021-01-29
  • 2021-11-23
相关资源
最近更新 更多