【问题标题】:How do I know when a child process died?我怎么知道子进程何时死亡?
【发布时间】:2011-04-10 04:39:10
【问题描述】:

在我的课堂上,我运行 4 个进程。

from multiprocessing import Process

    procs = (
             Process(target=ClassOne, name='ClassOne'),
             Process(target=ClassTwo, name='ClassTwo'),
             Process(target=ClassThree, name='ClassThree'),
             Process(target=ClassFour, name='ClassFour'),
            )

    for p in procs:
        p.daemon = False
        p.start()

我希望在我的一个子进程死亡时收到通知,以便我可以杀死另一个和我自己。

【问题讨论】:

    标签: python synchronization ipc process multiprocessing


    【解决方案1】:

    这是一个 Windows 解决方案。它使用WaitForMultipleObjects API 调用。对于 Unix,os.waitpid 可以完成这项工作。

    import multiprocessing as mp
    import ctypes
    
    
    SYNCHRONIZE = 0x00100000
    INFINITE = -1
    
    
    def mbox(msg):
      ctypes.windll.user32.MessageBoxW(0, msg, u'spam', 0)
    
    
    if __name__ == '__main__':
    
      # start 2 processes
      procs = [mp.Process(target=mbox, args=(msg,)) for msg in u'ab']
      for p in procs:
        p.start()
    
      # wait for at least one process to terminate
      handles = [
        ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE, False, p.pid)
        for p in procs]
      array_type = ctypes.c_long * len(handles)
      handle_array = array_type(*handles)
      ctypes.windll.kernel32.WaitForMultipleObjects(
        len(handles), handle_array, False, INFINITE)
    
      # terminate the rest
      for p in procs:
        p.terminate()
    
      # exit
      print 'done'
    

    【讨论】:

    • 问题是 waitpid() 只需要 one pid 并且在超时之前一直阻塞... WaitForMultipleObjects() 可以同时处理许多对象...您可以使用 waitpid() 提供 POC 吗?
    • @Spi,正如您显然自己发现的那样,waitpid 可用于等待“i-dont-care-which-one”孩子死去。问题是你可能已经产生了其他孩子,waitpid 也会发出他们终止的信号......
    【解决方案2】:

    最简单的方法是显式等待所有进程完成。

    while multiprocessing.active_children():
        pass
    

    这不是您可能想要的事件驱动,但它会在您的示例中完成工作。还要确保你import multiprocessing

    【讨论】:

    • OP 希望在至少一个孩子死亡时终止,而不是在他们全部死亡时终止。
    • 此解决方案将使用一个 CPU 忙于等待,并且无法解决@Constantin 指出的问题。
    【解决方案3】:

    只需为 SIGCHLD 定义一个信号处理程序,检查刚刚死去的孩子返回的帧以检索您需要的有关它的信息......如果需要,还可以退出()父母 :)

    【讨论】:

    • @Spi,如果您正在寻找特定于 Unix 的解决方案,您应该在问题中指出这一点。
    • @Constantin,Win没有信号?我真的很好奇,没有争论:)
    • Windows 有一个 C 信号 API,但本身并不使用它们。在 Windows 中,您可以轻松地等待子进程句柄。您只需等待第一个发出信号,然后终止其他人,然后自己退出。
    • 好吧,我猜你的回答暗示了类似signal.signal(SIGCHLD, handler)的东西。但是docs.python.org/library/signal.html 说“在 Windows 上,signal() 只能使用 SIGABRT、SIGFPE、SIGILL、SIGINT、SIGSEGV 或 SIGTERM 调用。在任何其他情况下都会引发 ValueError。”没有 SIGCHLD。
    • @Constantin,你是对的,我说的不是相反的......我在问你是否以及如何在 Windows 上处理信号,因为我不知道......@MSalters 解释得很清楚干净利落,多亏了他!
    【解决方案4】:

    可以使用os.waitpid() 传递-1 作为第一个参数,0 作为第二个参数。

    • 第一个参数表示请求属于当前进程的任何子进程。
    • 第二个参数表示它的行为类似于wait()

    该函数返回一个包含死孩子的 pid 及其退出代码的元组。

    【讨论】:

      【解决方案5】:

      您可能想查看this similar question 的答案中的 AutoJoiningProcess 类。

      如果您准备在代码中添加对 gobject(PyGTK 的一部分)的依赖项,那么 AutoJoiningProcess 将允许您监听进程完成时发出的信号。根据该信号,您可以随心所欲地做出响应。

      【讨论】:

        猜你喜欢
        • 2018-02-22
        • 1970-01-01
        • 2018-05-29
        • 1970-01-01
        • 2014-06-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多