Question

I've been reading the documentation on wait() and waitpid() and I'm still somewhat confused about how they work (I have gathered that wait(&status) is equivalent to waitpid(-1, &status, 0);). Below are some small snippets of code I'm working on. Please help me understand whether these snippets are written properly and if not then why not.

Goal 1: Reap all zombie children.

int reapedPid;
do {
    reapedPid = waitpid(-1,NULL,WNOHANG);
} while (reapedPid > 0);

What I'm trying to do here is iterate through all the children, reap the child if it's finished, let it keep going if it's not, and when I run out of children then reapedPid == -1 and the loop exits. The reason I'm confused here is that I don't see how waitpid() is supposed to know which children have already been checked and which have not. Does it do any such check? Or will this approach not work?

Goal 2: Wait for all children to finish.

int pid;
do {
    pid = wait(NULL);
} while (pid != -1);

Here I don't care what the resulting status is of the children - this should just keep waiting for every child process to finish, whether successfully or unsuccessfully, and then exit. I think this code is correct but I'm not sure.

Goal 3: Fork a child and wait for it to finish.

int pid = fork();
if (pid < 0) {
    // handle error.
}
else if (pid == 0) {
    // execute child command
}
else {
    int status;
    int waitedForPid = waitpid(pid,&status,0);
    assert(waitedForPid == pid);
}

Here I'm just trying to fork the process and have the parent wait for the child to finish. I am not entirely sure if I should be passing in the 0 option here but it seemed like WNOHANG, WUNTRACED, and WCONTINUED were not really relevant to my goal.

Was it helpful?

Solution

  1. It is the kernel's job to keep track of processes. Keeping track of dead processes is trivial. The kernel can tell which child processes have died but not yet been waited for, and will return one of those dead children on each call, until there are none left to report on. (Because of the WNOHANG option, there might still be children left to wait for, but none of the remaining children are dead, yet.)

  2. This second loop is also fine and almost equivalent to the first. The difference is that it will hang waiting for all the children to die before returning the -1.

  3. This third fragment is fine; the assertion will be true except in extraordinary circumstances (such as another thread in the program also waited for the child and collected the corpse). However, if you somewhere launched another process and let it run in the background, you might be collecting zombies, whereas with a modification of the other loops, you can collect the zombies and still wait for the correct child:

    int pid = fork();
    
    if (pid < 0)
    {
        // handle error.
    }
    else if (pid == 0)
    {
        // execute child command
    }
    else
    {
        int status;
        int corpse;
        while ((corpse = waitpid(-1, &status, 0)) > 0)
            if (corpse == pid)
                break;
    }
    

OTHER TIPS

For most of these, you should be able to easily code up some example programs and verify your understanding.

Goal 1: Reap all zombie children.

The reason I'm confused here is that I don't see how waitpid() is supposed to know which children have already been checked and which have not. Does it do any such check?

Once a child has exited, it can only be waited on once. So your loop will only get the exit status for child processes that have not yet been waited on (zombies).

For Goals 2 and 3, again, I would consider it a required exercise to code up an example to see how it works. For #2, I would instead suggest that your code should always keep track of all forked children, so that it can know exactly who to wait on. Your code for #3 looks good; no options are required. Remember to use the WEXITSTATUS and friends macros to get information from the status.

See also:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top