我在远程机器上运行一个守护进程:mydaemon。该守护进程应始终持续运行。
当我在远程机器上运行作业时,它还会启动一个轻量级 Python 服务器进程 my_remote_server.py。
我可以发送到 my_remote_server.py 的命令之一是重新启动 mydaemon,我正在尝试这样做:
os.system("killall mydaemon")
subprocess.Popen(["mydaemon"], stdin=None, stdout=None, stderr=None, close_fds=True)
当我的工作结束时,my_remote_server.py 应该终止,但 mydaemon 应该继续运行。但是我看到 my_remote_server.py 作为僵尸进程卡住了(这导致系统看不到我的工作已终止)
820 root Z [my_remote_serve]
834 root 552 S /usr/sbin/telnetd -l /bin/sh
835 root 836 S /bin/sh
844 root 672 S mydaemon
我想将父级 (my_remote_server.py) 与子级 (mydaemon) 分离,但我不知道该怎么做。
-- 我的python版本是2.5.4
编辑:
我想我现在对守护进程有了更好的理解,但我仍然无法让守护进程分离
为简洁起见,我在这里省略了错误处理
os.system("killall mydaemon")
if(os.fork() > 0):
return True # my_remote_server.py returns to handle additional commands
os.setsid()
if(os.fork() > 0):
exit(0) # first child exits after becoming session leader
os.execlp("mydaemon") # have the second child run as the daemon
这是我在调用 restart_mydaemon 函数之前的 ps 列表
252 root 672 S mydaemon
286 root 4552 S /usr/bin/python my_remote_server.py
这是在restart_mydaemon 之后,第一个 child 僵尸化了(它不应该消失了吗?)
286 root 4552 S /usr/bin/python my_remote_server.py
300 root Z [my_remote_serve]
304 root 672 S [mydaemon]
这是作业终止的时候(my_remote_server.py 应该已经退出,但它是一个僵尸,然而,此时第一个 child 已经退出)
286 root Z [my_remote_serve]
304 root 1012 S [mydaemon]
请您参考如下方法:
将一个进程变成一个守护进程是一个多步骤的过程。您的部分问题是您的父进程没有正确等待子进程终止(阅读 wait/waitpid),
- 您的进程必须关闭所有打开的文件描述符(stdin、stdout、stderr)
- 您的进程需要(更改目录、设置 umask,无论您想要/需要什么)
- 你必须 fork 一个进程
- 该流程必须成为流程组领导
您必须再次 fork ,以完全脱离(祖) parent
try: #free parent, detach from process group pid = os.fork() if( pid>0 ): exit(0) #parent exits except OSError, e: raise Exception("%s [%d]" % (e.strerror, e.errno)) #become session leader, process group leader, detach from controlling terminal os.setsid() try: #prevent zombie process, make init cleanup pid = os.fork() if( pid>0 ): exit(0) #parent exits except OSError, e: raise Exception("%s [%d]" % (e.strerror, e.errno)) #change directories, close stdin/out/err, etc os.chdir(MYDIR) os.umask(MYMASK) #close files (including stdin, stdout, stderr) #(re)open new stdin/stdout, if desired
