使用waitpid还是sigaction?

时间:2012-01-23 17:34:56

标签: c linux operating-system

我明白了: 1)waitpid用于等待孩子死亡,然后收集SIGCHLD和孩子的退出状态等。 2)当我们有一个SIGCHLD的信号处理程序时,我们会做更多与清理孩子或其他东西有关的事情(由程序员决定),然后做一个waitpid,这样孩子就不会去僵尸然后返回。

现在,当我们执行fork / exec并且子进程返回时,我们是否需要在程序中同时使用1和2? 如果我们同时拥有这两者,则首先获取SIGCHLD,因此首先调用信号处理程序,因此成功调用其waitpid而不是父进程代码中的waitpid,如下所示:

my_signal_handler_for_sigchld
{
do something
tmp = waitpid(-1,NULL,0);
print tmp (which is the correct value of the child pid)
}

int main ()
{
  sigaction(SIGCHLD, my_signal_handler_for_sigchld)
  fork()
  if (child) //do something, return
  if parent // waitpid(child_pid, NULL,0); print value returned from this waitpid - it is -1
}

感谢有人帮我理解这一点。

2 个答案:

答案 0 :(得分:19)

如果你的意图是运行子进程,做一些事情,然后等待它完成,你真的不需要处理SIGCHLD。在这种情况下,您只需在准备好同步时调用waitpid即可。 SIGCHLD唯一有用的是子终止的异步通知,例如,如果您有一个交互式(或长时间运行的守护程序)应用程序,它会生成各种子项并需要知道它们何时完成。但是,SIGCHLD对于此目的来说也非常糟糕/丑陋,因为如果您使用创建子进程的库代码,则可能会捕获库的子进程终止并干扰其处理的事件。信号处理程序本质上是进程全局的,处理全局状态,通常是一个坏事(tm)。

当您有子进程异步终止时,有两种更好的方法:

方法1(基于select / poll基于事件):确保您有一个管道往/来自您创建的每个子进程。它可以是他们的stdin / stdout / stderr,也可以只是一个额外的虚拟fd。子进程终止时,管道的末尾将关闭,主事件循环将检测该文件描述符上的活动。从它关闭的事实来看,你认识到儿童过程已经死亡,并致电waitpid收获僵尸。

方法2(基于线程):对于您创建的每个子进程,还要创建一个线程,该线程将立即在子进程的pid上调用waitpid。当waitpid成功返回时,使用您最喜欢的线程同步原语让程序的其余部分知道子进程终止,或者只是在终止之前处理这个服务器线程中需要做的所有事情。

这两种方法都是模块化和库友好的(它们可以避免干扰代码或库代码中可能正在使用子进程的任何其他部分。)

答案 1 :(得分:1)

你需要调用等待的系统调用,例如waitpid或朋友 - 例如wait4等,否则你可以zombie processes

您可以处理SIGCHLD以通知某个孩子已经结束(或停止等等),但您需要稍后等待。

信号处理程序仅限于调用一小组异步信号安全函数(有关详细信息,请参阅signal(7))。好的建议是在里面设置一个volatile sig_atomic_t标志,并在以后更安全的地方进行测试。