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

Viewed 615

I have the following piece of code:

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

When I try to execute it, I receive a SIGKILL error, instead of getting 8 Text messages, from the fork call. However, If I change

while(wait(NULL)){}

to

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

or

while(wait(NULL) > 0){}

I'm receiving 8 "Text" prints as expected.

Why isn't the program working in the first case? Isn't wait(NULL) loop or wait(0) loop supposed to wait until all child processes are finished executing?

Thanks for the help!

4 Answers

When you do this:

while(wait(NULL)){} 

It's the same as:

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

The wait function returns the child pid on success or -1 on error. So the return value will never be 0. This results in an infinite loop.

Doing this:

while(wait(NULL) > 0){}

Will loop as long as a child returns, and quit when -1 is returned.

A few things ...

You're doing fork in a loop but you're not separating the parent/child actions. That is, both finish the loop and both parent and child try to wait for completion.

You probably want to do the wait only in the parent.

wait(NULL) will suspend/wait for the next child to complete (i.e. not all of them). That's why you have to loop.

The return from wait is the pid of the child process that just exited [which is > 0]. If error, -1 is returned. If there are no more child processes to wait on, wait will return -1 (with errno set to ECHILD).

So, while (wait(NULL) > 0) is your best bet.


Adding some printf statements may help with your understanding:

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

Here's the output:

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) {}

Awaits for all child processes to finish, when no child process is left, a -1 is returned which breaks the while as -1 > 0 is false. Look at wait man page. Which in the first case is causing an infinite loop as -1 is evaluated as true.

pid_t wait(int *wstatus);

system calls are used to wait for state changes in a child of the calling process, and obtain information about the child whose state has changed. The wait(&status) system call has two purposes. First, if a child of the calling process has not yet terminated by calling exit(), then wait() suspends execution of the process until one of its children has terminated. Second, the termination status of the child is returned in the status argument of wait().

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

on success, returns the process ID of the terminated child; on error, -1 is returned.

while(wailt(null)>0){
}

this means that we are waiting for all childrens to terminate in a success condition! upon first error we will exit the while and if the calling process have more childrens that didnt terminated yet, we will not wait for them which later , the terminated childs remains in a "zombie" state.

while(wailt(null)){
}

this means that even if errors happens on witing for one of the childs, (due to The options argument was invalid for example or any other reason see documentation), we will keep waiting untell the last child termination.

man7_wait()

Related