如何使父进程等待所有子进程完成?

90

我希望有人能够解释一下如何让父进程在fork之后等待所有子进程完成后再继续。我有清理代码需要运行,但必须在子进程返回后才能执行。

for (int id=0; id<n; id++) {
  if (fork()==0) {
    // Child
    exit(0);      
  } else {
    // Parent
    ...
  }
  ...
}

6
如果你关心哪个子进程何时退出,那么从所有这些 fork 中返回的 pid 对于你的任务尤为有用。否则,使用 wait() 函数等待执行 n 次即可。 - WhozCraig
4个回答

96
pid_t child_pid, wpid;
int status = 0;

//Father code (before child processes start)

for (int id=0; id<n; id++) {
    if ((child_pid = fork()) == 0) {
        //child code
        exit(0);
    }
}

while ((wpid = wait(&status)) > 0); // this way, the father waits for all the child processes 

//Father code (After all child processes end)

wait 等待一个子进程终止,并返回该子进程的 pid。如果出现错误(例如没有子进程),则返回 -1。因此,基本上代码会一直等待子进程完成,直到 wait 出错,然后你就知道它们全部都已经完成了。


1
我想知道是否可以安全地假定“等待期间出错”等同于“没有更多要等待的子进程”。 - Twonky
man 2 wait 说:ECHIILD (for wait()) The calling process does not have any unwaited-for children. 我认为你可以 #include <errno.h> 并在 while 循环中使用它。 - Not me

44

POSIX定义了一个函数:wait(NULL);。它是waitpid(-1, NULL, 0);的简写形式,该函数会挂起调用进程的执行,直到任何一个子进程退出。

在您的情况下,父进程应在else分支中调用它。


谢谢您的回复。我在非子进程部分添加了wait(NULL),但程序卡住了,子进程甚至没有执行? - Donatello
1
哦,那不是wait()函数的错误。你应该把完整的代码放上来让我调试。你的代码太简单了,只是一个模型。 - xxx7xxxx
14
wait 的 man 手册说它等待一个子进程终止。如@WhozCraig在上面提到的,你需要 wait n 次。 - Greg Dunn
这是有关 wait 调用的更详细解释:http://man7.org/linux/man-pages/man2/waitpid.2.html - trinity420
5
为了让进程等待全部子进程终止,我使用了while(wait(NULL) > 0); - kotchwane
如果您这样做,那么如果调用wait()的进程接收到信号会发生什么?根据wait()的手册,如果wait()waitpid()由于向调用进程传递信号而返回,则应返回-1并将errno设置为[EINTR]。 - adentinger

26

像这样使用waitpid():

pid_t childPid;  // the child process that the execution will soon run inside of. 
childPid = fork();

if(childPid == 0)  // fork succeeded 
{   
   // Do something   
   exit(0); 
}

else if(childPid < 0)  // fork failed 
{    
   // log the error
}

else  // Main (parent) process after fork succeeds 
{    
    int returnStatus;    
    waitpid(childPid, &returnStatus, 0);  // Parent process waits here for child to terminate.

    if (returnStatus == 0)  // Verify child process terminated without error.  
    {
       printf("The child process terminated normally.");    
    }

    if (returnStatus == 1)      
    {
       printf("The child process terminated with an error!.");    
    }
}

8
这并不等待所有孩子都完成,只等待一个特定的孩子childPid。如果有更多的进程,这种方法就行不通了。 - JH95
1
当然,如果您从单个父进程创建多个线程,则必须相应地修改此示例。提供几个fork的示例会使我的答案看起来混乱。 - Jason Enochs
2
你会如何修改这段代码,使得父进程等待所有子进程都执行完毕? - OutFall
@JasonEnochs 我认为修改示例以进行多个fork并不是一件简单的事情。如果您的代码只是“循环”了n次(将waitpid调用放在forking循环中),那么我认为我们会得到子进程的串行执行,也许这并不是期望的结果。下面@adrisons的答案看起来不错。 - rocarvaj

5

只需要使用:

while(wait(NULL) > 0);

这可以确保你等待所有的子进程,只有当它们都返回时,你才会继续执行下一条指令。

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