我有一个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
将杀死它及其所有子进程(假设您没有做任何花哨的操作)。