我正在开发一个将集成到客户端代码中的库(C++)。此库将生成一些子进程,并且必须监视它们,以便在它们死亡后立即重生它们(出于任何原因)。我需要使用 vfork 和 exec 来生成这些子进程。
我知道我必须使用信号处理程序来处理 SIGCHLD 并调用 waitpid 来检测哪个孩子已经死亡。但是,用户代码可能使用相同的想法来处理自己的子进程。
如果我调用waitpid,我将检索有关任何可能死亡的子进程(我的或不是我的)的信息。如果死亡过程是我的,没问题...快乐的案例。但是,如果它来自用户,他不会获得任何相关信息,因为我已经调用了waitpid。
我该如何解决这个问题?
我的第一个想法是使用进程组。第一次分叉时,我会获取子 pid 并将其另存为进程组 ID。我创建的每个孩子,我都会将其组设置为此pid。你们认为这是一个不错的选择吗?(我对此有麻烦)。
我的第二个想法是将信号处理程序重置为原始处理程序(或只是调用它)。如果我重新发出信号,原始处理程序将能够获得它。在那之后,我必须重新安装我的信号处理程序。会是一个不错的选择吗?
我的第三个选择是使用INFO(扩展信号处理程序)。我相信死亡过程的pid将在信息结构中可用。如果这是我的一个孩子,我会打电话给waitpid,没关系。如果这不是我的一个,我会调用原始信号处理程序。会是一个不错的选择吗?
只是最后一个侧面问题。为了能够调用原始信号处理程序,我应该始终恢复它们并重新发出信号,还是仅将其作为函数调用就足够了?
非常感谢您的帮助。
另一种选择可能是先生成一个子进程,该子进程通过您喜欢的任何 IPC 机制与您的主进程通信。然后,从该新进程中生成多个子进程,这使您可以完全控制子进程的终止方式。
如果它是一个通用库(对于任何第三方),你应该尽量避免这样的结构。如果无法避免其使用,请非常非常仔细地记录信号处理。
如果与 lib 链接的程序播放信号,则可能会出现许多复杂的情况,而 lib 只是没有机会正确处理它们,而不会以意想不到的方式影响程序。考虑程序可能有多个线程或处理您没有的其他信号:在任何一种情况下,它都可能同时更改SIGCHILD
的信号处理并破坏您的逻辑。
lib 中提供一个函数,让它在信号SIGCHILD
(对于您创建的 PID)到来时调用它,这样程序仍然可以自由地按照它的意愿处理它的信号。
这篇文章只是为了澄清我的解决方案。
我决定不再在主进程中使用信号处理程序。除非必要,否则库不应处理信号。
在主进程中,我创建了一个管道,调用一个单独的二进制文件,它将自己变成一个执事。这样,由此生成的进程就不会是主进程的子进程。
要把它变成一个恶魔,我只是分叉它。分叉的父级只是打印子进程的 PID,以便主进程可以将其取回(通过管道)。子进程将掩码设置为零,创建新的 SID,将当前目录更改为"/",然后重新打开 STDIN、STDOUT 和 STDERR(全部为/dev/null)。这样,孩子现在就是一个执事。
这个恶魔负责生成我的所有进程。所有这些(包括执事)都使用套接字与主进程通信。
主要进程向守护进程发送信号(SIGINT 关闭它及其所有子进程,SIGUSER1和 2 发送到预定义的操作)。
感谢所有在这里提供帮助的人。