Linux fork() and wait()

百般思念 提交于 2019-12-05 14:22:26

Here's a demo of the easiest way to produce the output in the order you asked for. It uses 3 loops: one to create the child processes, one to wait for them and collect their exit statuses, and one to print the exit statuses.

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

#define NUMPROC 5

int main(void)
{
  pid_t child[NUMPROC];
  int status[NUMPROC];
  int i;

  printf("parent = %d\n", getpid());

  for(i=0;i<NUMPROC;++i) {
    if(fork() == 0) {
      sleep(i);
      printf("i=%d, %d\n",i, getpid());
      _exit(0);
    }
  }

  for(i=0;i<NUMPROC;++i)
    child[i] = wait(&status[i]);

  for(i=0;i<NUMPROC;++i)
    printf("Exit = %d, child = %d\n", WEXITSTATUS(status[i]), child[i]);
}

This isn't a problem with wait(), it's a matter of synchronization — or lack thereof. Each time you call fork(), your child process sleeps for awhile, but the parent process continues executing. Your parent process finishes its fork loop and starts its wait loop while most of the children are still sleeping, so each time one of the children exits, the parent is already waiting for it. That's why the parent process is able to print its exit message immediately after each child exits.

If you want your parent process to wait for all the children to finish sleeping before entering the wait() loop, you'll need to need to use an IPC synchronization mechanism, such as POSIX semaphores, to make the parent process block until all children have signaled that they're ready.


However, if your goal is simply to have all the exit messages appear on the screen after the child ID messages, you don't really need to delay the wait() calls at all. Just change the wait loop to store the status values in an array instead of immediately printing them, and then after the wait loop finishes, run another loop to print the contents of the array.

You are correct. wait will return when any child exits. If you want to wait until all children have exited you can repeat the wait call in a while loop until it returns -1 and errno = ECHILD, which means no more children exist.

while (! (wait (0) == -1 && errno == ECHILD) ) ;

This loop is a little simplistic. You presumably want to check the result of your processes, and you should handle other errors that could occur.

wait (0) waits for any child process to change status, not for all processes to change status. You have to store the pid-s of your child processes and then wait for each of them in a for loop:

i_am_child = 0;
my_i = 0;
for (i = 0; i < nr_children; ++i) {
    child = fork ();
    if (child == 0) { i_am_child = 1; my_i = i; break; }
    childpid [i] = child;
}
if (i_am_child) {
    // do what children are supposed to do, e.g. printf and sleep (my_i)
    exit (0);
}
if (! i_am_child) // strictly, this line is not necessary, since children have exited
    for (i = 0; i < nr_children; ++i) waitpid (childpid [i], &status, 0);
...

Make sure that the forks and waits are executed by the parent only!

As far as I see, the children should break the first for loop immediately after the fork and not enter the second.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!