多进程守护进程未在父进程退出时终止



我有一个Python 2.7多进程,它不会在父进程退出时退出。我设置了守护标志,它会在父进程死亡时强制退出。文档声明:

"当一个进程退出时,它试图终止它所有的守护子进程。"

p = Process(target=_serverLaunchHelper, args=args)
p.daemon = True
print p.daemon # prints True
p.start()

当我通过kill命令终止父进程时,守护进程仍然处于活动状态并正在运行(这会在下次运行时阻塞端口)。子进程启动SimpleHttpServer并调用serve_forever,而不做任何其他事情。我的猜测是,文档中的"尝试"部分意味着阻塞服务器进程正在阻止进程死亡,从而使进程成为孤儿。我可以让子线程将服务推送到另一个线程,并让主线程检查父进程id的更改,但这似乎只是复制守护进程功能的大量代码。

有人知道为什么守护进程标志没有按照描述工作吗?在windows8 64位和ubuntu12 32位虚拟机上可重复此操作。

流程函数的简化版本如下:

def _serverLaunchHelper(port)
    httpd = SocketServer.TCPServer(("", port), Handler)
    httpd.serve_forever()

当一个进程退出时,它试图终止它所有的守护子进程。

这里的关键词是"尝试"。此外,"出口"。

根据您的平台和实现,终止守护子进程的唯一方法可能是显式地这样做。如果父进程正常退出,它就有机会显式退出,所以一切正常。但是,如果父进程突然终止,则不会。

特别是对于CPython,如果你查看源代码,终止守护进程的处理方式与加入非守护进程的处理方式相同:通过在atexit函数中遍历active_children()。因此,当且仅当您的atexit处理程序运行时,您的守护进程才会被杀死。并且,正如该模块的文档所说:

注意:当程序被Python不处理的信号终止时,当检测到Python致命内部错误时,或者当调用os._exit()时,通过该模块注册的函数不会被调用。

根据你如何杀死父进程,你可以通过添加一个信号处理程序来拦截突然终止来解决这个问题。但是你可能不会。,在POSIX上,SIGKILL是不可拦截的,所以如果你设置了kill -9 $PARENTPID,这不是一个选项。

另一个选择是杀死进程组,而不仅仅是父进程。例如,如果父进程的PID为12345,linux上的kill -- -12345将杀死它及其所有子进程(假设您没有做任何花哨的操作)。

最新更新