我正在编写一个进程管理器,用于监视其子进程并在必要时重新启动它们。
目前,我有
pidfd
与每个正在运行的进程相关联,并且 epoll
正在等待所有这些 pidfd
。当一个进程终止时,epoll_wait()
被唤醒,为了确定进程的退出代码,我使用阻塞waitpid()
来确定我的进程`退出代码(在我的程序中,需要确定是否重新启动进程或不是)。
我想知道我的解决方案是否存在任何潜在问题,因为我必须使我的流程管理器尽可能无锁且安全。我主要关心的是在
waitpid()
变得可读后使用 pidfd
。有没有可能这个等待会锁定我的执行?
如果您能就我的问题提供任何帮助、见解或反馈,我将不胜感激。
总的来说,你的做法是正确的。
以下情况可能会导致故障:
wait
/waitpid
,并在 epoll 响应式 waitpid
调用运行之前“窃取”给定子进程的收获。如果您的代码是一个独立的程序,并且您可以确定不存在这样的线程,那么您可能是安全的。在一些严重面向事件循环的运行时(nodejs和Python中的uvloop,Python的Popen
和multiprocessing
)中可能存在这样的收割者线程。如果您正在使用这些运行时之一,请小心。SIGCHLD
信号处理程序,它会自动调用
wait
/
waitpid
来响应接收到的信号。这与上面的线程情况类似,但通过不同的机制。许多高级编程语言的运行时(例如 Python、Go)都会安装这样的处理程序。如果您的运行时这样做,它可能还提供了一种取消设置或禁用此行为的方法;如果是的话,请检查文档。您的程序已将
SIGCHLD
处理设置为
SIG_DFL
,其中
sigaction
为
SIG_IGN
,或者设置了
sigaction
为
SIG_NOCLDWAIT
。这些条件启用了“自动收割”子进程。在此模式下,
wait
和
waitpid
不是必需的,调用它们将始终阻塞。这在野外比较罕见。
如果您的程序与其他任意代码集成,那么按照 Shawn 在评论中建议的方式进行操作可能是有意义的,并且通过设置
waitpid
标志来完成对
WNOHANG
的 epoll 响应式调用。这样,如果
waitpid
的结果表明其他东西已经收割了子进程,您可以报告错误或警告,而不是停止整个流程管理器。这就是 Python 中的
PidfdChildWatcher
所做的事情,因为很难保证 Python 中的程序不会造成上面列出的任何情况。