我有一个 python 程序,用于subprocess.Popen
启动另一个进程(python 进程或其他),在启动它之后,我将孩子的 PID 保存到一个文件中。让我们假设父进程突然死亡(由于异常或其他原因)。有没有办法再次访问返回的对象Popen
?
我的意思是,基本思想是首先读取文件,如果它存在并且上面写有 PID,然后以某种方式访问该进程,以便知道返回码或其他什么。如果没有 PID,则使用Popen
.
非常感谢!!
Popen 对象实际上只是子进程 PID、stdin、stdout 和 stderr 的包装器,以及一些使用它们的便利函数。
所以问题是为什么你需要访问 Popen 对象?你想与孩子沟通,终止它,还是检查它是否仍在运行?
在任何情况下,都没有办法为已经运行的进程重新获取 Popen 对象。
解决这个问题的正确方法是将孩子作为守护进程启动,就像 Tobu 建议的那样。守护进程的部分过程是关闭标准输入和标准输出,因此您不能使用它们与子进程对话。相反,大多数守护进程使用管道或套接字来允许客户端连接到它们并向它们发送消息。
与子进程对话的最简单方法是从子进程打开一个命名管道,例如 /etc/my_pipe,从父/控制进程打开该命名管道,然后对其进行写入/读取。
在快速浏览一下 python-daemon 之后,在我看来,python-daemon 将帮助您守护您的子进程,这很难做到正确,但它并不能帮助您处理消息方面的事情。
但就像我说的那样,我认为您需要告诉我们为什么您需要一个 Popen 对象用于子进程,然后我们才能进一步帮助您。
如果一个进程死亡,它所有打开的文件句柄都将关闭。这包括由popen()
. 所以,不,没有办法Popen
从 PID 中恢复对象。操作系统甚至不会将您的新进程视为父进程,因此您甚至不会收到SIGCHLD
信号(尽管waitpid()
可能仍然有效)。
我也不确定孩子是否能保证存活,因为写入没有阅读器的管道(即,stdout
孩子的重定向)应该用SIGPIPE
.
如果您希望您的父进程从子进程停止的地方开始,您需要生成子进程以写入文件,通常在/tmp
or/var/log
中,并让它像现在一样记录其 PID(通常的位置是/var/run
)。(将其写入命名管道可能会导致它SIGPIPE
像上面那样被杀死。)如果您使用 PID 为文件名添加后缀,那么管理器进程很容易确定哪个文件属于哪个守护进程。
看起来你正在尝试编写一个守护进程,它需要 pidfile 支持。python-daemon不会出错。
例如:
import daemon
import lockfile
import os
with daemon.DaemonContext(pidfile=lockfile.FileLock('/var/run/spam.pid')):
os.execl('/path/to/prog', args…)