等待所有子进程完成后,父进程才能恢复执行 UNIX。

13

我在程序中使用有限的while循环并通过fork(并行)子进程,在每个子进程上执行exec。我希望只有在所有子进程终止后,父进程才恢复执行(即此while循环之后的点)。我该怎么做?

我尝试了几种方法。在一种方法中,我让父进程在while循环后暂停,并从SIGCHLD处理程序发送某些条件,仅当waitpid返回错误ECHILD(没有剩余的子进程)时才会发生。但是我在这种方法中遇到的问题是,即使在父进程完成fork所有进程之前,retStat也会变为-1。

    void sigchld_handler(int signo) {
        pid_t pid;
        while((pid= waitpid(-1,NULL,WNOHANG)) > 0);
        if(errno == ECHILD) {
            retStat = -1;
        }
    }

    **//parent process code**
    retStat = 1;
    while(some condition) {
       do fork(and exec);
    }

    while(retStat > 0)
        pause();
//This is the point where I want execution to resumed only when all children have finished
2个回答

22

在信号处理程序中,为什么不在您 fork 所有进程之后创建如下循环,而不是调用 waitpid

while (pid = waitpid(-1, NULL, 0)) {
   if (errno == ECHILD) {
      break;
   }
}
程序应该在循环中挂起,直到没有更多的子进程。然后它会跳出循环,程序将继续运行。作为额外的奖励,当子进程正在运行时,循环将在waitpid上阻塞,因此您无需在等待时使用忙循环。您还可以使用wait(NULL),这应该等同于waitpid(-1, NULL, 0)。如果在SIGCHLD中没有其他需要做的事情,则可以将其设置为SIG_DFL。

我需要给出WNOHANG选项,因为如果有很多子进程几乎同时发送SIGCHLD信号,并且由于UNIX中的信号不会排队,如果我使用0,则只能捕获一个信号,然后僵尸进程将留在周围。 - avd
只是补充一点,-1 将检查任何子进程 pid(也可以使用 WAIT_ANY 来提高清晰度)。 - amischiefr
@aditya:僵尸进程只是在等待您调用wait()(或wait_pid())函数。一旦您这样做了,它们就会消失,无论您是否捕获了信号。因此,在fork()循环之后的wait()循环将清理所有僵尸进程。 - Jeremy Bourque
同意 - 如果您正在使用wait/waitpid,则不需要自己处理SIGCHLD - mob

0

我认为你应该使用waitpid()调用。它允许你等待“任何子进程”,所以如果你这样做了适当的次数,你应该就可以了。

如果那行不通(不确定保证),你可以采取蛮力方法,在循环中执行waitpid(),并对每个子PID使用NOHANG选项,然后延迟一段时间再重复执行。


请看代码,我已经按照您所说的做了完全相同的事情。 - avd
@aditya:嗯,不,我的建议是像jborque建议的那样做,我没有提到使用信号处理程序。 - unwind

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