如何检查一个进程的pid X是否为僵尸进程?

4
我得到了进程的PID,需要使用C语言中的POSIX系统调用来检查它是否为僵尸进程。我该怎么做?
我的问题是,我有一个进程,它会分叉出许多子进程,这些子进程都会执行execs操作,有时我想在后台执行execs操作,所以我不能真正地等待在后台运行的子进程。我可以定期地(在主循环中)调用wait()函数,但是我需要知道哪些进程是僵尸进程,这样我的父进程就不会一直等待那些不会很快结束的子进程而挂起。
如果您感兴趣,我正在构建一个Unix shell,它的性质是要使子进程异步执行。
5个回答

6
你不能使用纯POSIX调用来检查一个进程是否为僵尸进程 - 除非你是父进程,并使用wait家族调用来回收它。因此,你需要找到一个好的地方等待子进程。
一种选择是设置SIGCHLD处理程序,在那里执行waitpid(0, &status, WNOHANG)。确保循环直到它不再发现任何进程 - 如果两个子进程在短时间内死亡,你可能只会得到一个SIGCHLD
另一种选择是双重fork - 即fork(),让子进程(称其为子进程A)再次fork,让第二个子进程(子进程B)执行。然后,子进程A立即退出。同时,父进程正在等待子进程A。一旦子进程A消失,系统的init进程将在子进程B最终死亡时负责回收它。这种方法更简单,但你的shell无法知道子进程B何时死亡,因此如果你需要该信息,请使用前一种方法。

谢谢,我正在使用您的第一个建议。您的第二个建议也很有趣,但由于双重分叉可能会导致性能下降,因此实施起来可能会很麻烦。 - Hoffmann
2
在许多(大多数?)现代类Unix系统上,Forking非常快速,并且采用了许多技巧(这是内核的核心)。请不要在没有性能分析的情况下将其判断为“缓慢”。 - user166390

3

但是..但是..这个僵尸进程在某种程度上是一个子进程,而检查进程是父进程,对吧?所以如果你关心一个特定的pid是否是僵尸进程,为什么不使用waitpid(2)WNOHANG来处理它呢?现在,这将消耗退出状态,因此,如果其他进程将来可能真正想要等待它,这可能是一个坏主意。


谢谢,我不知道wait在那个选项(顺便说一下,它是WNOHANG)下能立即返回。 - Hoffmann

1

1
有趣的论文。我质疑Emacs是否在半烹饪模式下运行,其中按键仍会生成信号;大多数基于curses的程序都使用原始模式终端设置运行,在这种情况下,终端驱动程序不会向程序发送SIGINT或SIGQUIT信号;程序只是像任何其他控制字符一样获取按键。 - Jonathan Leffler
Emacs确实可以从按键接收信号。它还将C-g (^G)重新分配为SIGINT的键,最后我检查过它会做一些非常恶心的不可移植的longjumping-out-of-signal-handlers的事情... - R.. GitHub STOP HELPING ICE

1

通常,shell 在打印提示符之前会检查僵尸进程 - 使用 waitpid(2) 系统调用和已经讨论过的 WNOHANG 选项。你可能还需要一个 SIGCHLD 处理程序 - 但是如果你正在忙于等待某个前台进程终止,而实际上它是一个后台进程终止,那么你必须决定如何处理这些信息。

这只是当前所选答案的一个小变化。


0

那么关于显示活动进程表的shell命令'ps',您能找到一个进程是'defunct'吗?我想从c代码中获取这些信息一定有办法。


我想你可以使用system()调用并解析结果,但这将取决于平台(也取决于系统是否安装了ps命令,这并不保证)。ps程序不是POSIX规范的一部分。此外,调用外部程序将涉及字符串解析和fork另一个进程,这将非常缓慢和丑陋。 - Hoffmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接