Linux fork()和wait()

时间:2014-03-16 00:10:47

标签: c linux fork wait

我有一个难闻的问题:(

我有这段代码:

int main()
{
    pid_t child, parent;        
    int status=0;
    int i;

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

    for(i=1; i<=5; i++){
        if( (child = fork()) == 0){
            sleep(i);
            printf("i=%d, %d\n",i, getpid());
        }
    }
    wait(0);
    while( (parent = wait(&status)) > 0){
        printf("Exit = %d, child = %d\n", status/256, parent);
    }    
}

和输出类似于:

    1, 21320
    2, 21321
    Exit = 0, child = 21321
    3, 21322
    Exit = 0, child = 21322
    4, 21323
    Exit = 0, child = 21323
    5, 21324
    Exit = 0, child = 21324

我认为wait(0)不等待所有子进程但只等待第一次退出并写入all(Exit = ...)。

有没有办法做到这一点:

    1, 21320
    2, 21321
    3, 21322
    4, 21323
    5, 21324

    Exit = 0, child = 21320
    Exit = 0, child = 21321
    Exit = 0, child = 21322
    Exit = 0, child = 21323
    Exit = 0, child = 21324

4 个答案:

答案 0 :(得分:4)

以下是按照您要求的顺序生成输出的最简单方法的演示。它使用3个循环:一个用于创建子进程,一个用于等待它们并收集它们的退出状态,另一个用于打印退出状态。

#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]);
}

答案 1 :(得分:3)

这不是wait()的问题,而是同步问题 - 或者缺乏同步问题。每次调用fork()时,您的子进程都会休眠一段时间,但父进程会继续执行。您的父进程完成其fork循环并开始其等待循环,而大多数子进程仍处于休眠状态,因此每次其中一个子进程退出时,父进程已经在等待它。这就是为什么父进程能够在每个子进程退出后立即打印其退出消息的原因。

如果您希望父进程在进入wait()循环之前等待所有子进程完成休眠,则您需要使用IPC同步机制,例如POSIX semaphores ,使父进程阻止,直到所有孩子都发出信号表明他们已做好准备。


但是,如果您的目标只是让孩子ID消息后屏幕上显示所有退出消息,那么您根本不需要延迟wait()来电。只需更改wait循环以将状态值存储在数组中而不是立即打印它们,然后在wait循环结束后,运行另一个循环来打印内容数组。

答案 2 :(得分:2)

wait (0)等待任何子进程更改状态,而不是所有进程更改状态。您必须存储子进程的pid-s,然后在for循环中等待它们中的每一个:

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);
...

确保叉子和等待仅由父母执行!

据我所知,孩子们应该break第一个for循环,然后不进入第二个。

答案 3 :(得分:2)

你是对的。等待将在任何孩子退出时返回。如果你想等到所有孩子都退出,你可以在while循环中重复等待调用,直到它返回-1并且errno = ECHILD,这意味着不再存在子节点。

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

这个循环有点简单。您可能想要检查进程的结果,并且应该处理可能发生的其他错误。