使用 fork 时 while(wait(NULL)){} 和 while(wait(NULL) > 0){} 有什么区别

What's the difference between while(wait(NULL)){} and while(wait(NULL) > 0){} when using fork

我有如下一段代码:

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

int main() {
for(int i = 0; i <3; i++){
    fork();
}
while(wait(NULL)){}
printf("Text\n");
return 0;
}

当我尝试执行它时,我收到一个 SIGKILL 错误,而不是从 fork 调用中收到 8 条文本消息。但是,如果我改变

while(wait(NULL)){}

while(wait(NULL) == 0){} 

while(wait(NULL) > 0){}

我按预期收到了 8 份“文本”打印件。

为什么程序在第一种情况下不工作? wait(NULL) 循环或 wait(0) 循环不是应该等到所有子进程都执行完吗?

感谢您的帮助!

当你这样做时:

while(wait(NULL)){} 

等于:

while(wait(NULL) != 0){} 

wait 函数 return 成功时为 child pid,错误时为 -1。所以 return 值永远不会为 0。这会导致无限循环。

这样做:

while(wait(NULL) > 0){}

只要 child returns 就会循环,并在 returned -1 时退出。

几件事...

您正在循环执行 fork 但您 没有 将 parent/child 操作分开。也就是说,both 完成循环并且 both parent 和 child 尝试 wait 完成。

您可能只想在 parent 中执行 wait

wait(NULL) 将 suspend/wait 用于 下一个 child 完成(即 不是 所有其中)。这就是为什么你必须循环。

来自 wait 的 return 是刚刚退出的 child 进程的 pid [> 0]。如果错误,-1 是 returned。如果没有更多 child 个进程等待,wait 将 return -1(errno 设置为 ECHILD)。

所以,while (wait(NULL) > 0) 是你最好的选择。


添加一些 printf 语句可能有助于您的理解:

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

int
main()
{
    pid_t pid;

    setbuf(stdout,NULL);

    printf("parent: my pid is %d\n",getpid());

    for (int i = 0; i < 3; i++) {
        pid = fork();
        if (pid != 0) {
            printf("%d forked %d\n",getpid(),pid);
        }
        else {
            printf("child: %d\n",getpid());
        }
    }

    while ((pid = wait(NULL)) > 0) {
        printf("%d: wait on %d\n",getpid(),pid);
    }

    printf("Text (from %d)\n",getpid());

    return 0;
}

这是输出:

parent: my pid is 469844
469844 forked 469845
child: 469845
469844 forked 469846
child: 469846
469844 forked 469848
469845 forked 469847
child: 469848
469846 forked 469849
Text (from 469848)
469845 forked 469850
child: 469849
child: 469850
Text (from 469849)
Text (from 469850)
child: 469847
469844: wait on 469848
469847 forked 469851
469845: wait on 469850
child: 469851
469846: wait on 469849
Text (from 469846)
Text (from 469851)
469844: wait on 469846
469847: wait on 469851
Text (from 469847)
469845: wait on 469847
Text (from 469845)
469844: wait on 469845
Text (from 469844)
while(wait(NULL) > 0) {}

等待所有子进程完成,当没有子进程剩余时,返回一个 -1 中断 while,因为 -1 > 0 为 false。查看 wait 手册页。在第一种情况下导致无限循环,因为 -1 被评估为 true。

pid_t wait(int *wstatus);

系统调用用于等待调用进程child的状态变化,并获取状态发生变化的child的信息。 wait(&status) 系统调用有两个目的。首先,如果一个child的调用进程 尚未通过调用 exit() 终止,然后 wait() 暂停执行 进程,直到其 children 之一终止。二、终止状态 在 wait().

的状态参数中返回 child 的

No when wstatus is NUll no status information well being stored!

成功时,returns 终止的进程 ID child;出错时返回 -1。

while(wailt(null)>0){
}

这意味着我们正在等待所有 children 在成功条件下终止!出现第一个错误时,我们将退出 while,如果调用进程有更多尚未终止的 children,我们将不会等待它们,稍后终止的 childs 仍处于“僵尸”状态.

while(wailt(null)){
}

这意味着即使在 child 之一的 witing 中发生错误(例如由于选项参数无效或任何其他原因参见文档),我们将继续等待直到最后一个child终止。

man7_wait()