Search code examples
clinuxforkwaitsystems-programming

Does wait(0) do anything when called from both processes created from fork()?


I'm trying to understand how fork works, and I know that when you call fork() another process is created that resumes from the exact same line with the heap and stack copied to it. For the parent, fork() returns the PID of the child and for the child it returns 0.

I stumbled across this question: "How many processes does the following sequence create?"

fork();fork();wait(0);fork();wait(0);

The answer is 8, including the parent, but I do not clearly understand if wait(0) actually waits or not. I found this related to the manual of "wait":

If there are at least one child processes running when the call to wait() is made, the caller will be blocked until one of its child processes exits. At that moment, the caller resumes its execution. If there is no child process running when the call to wait() is made, then this wait() has no effect at all. That is, it is as if no wait() is there.

My understanding of this can be drawn as such:

enter image description here

Where the leftmost branch is the parent and the black circles are where forks were made. This makes me believe that the wait(0)'s do nothing because there are no children to wait for, so it's simply ignored. However, i made a little modification to the code, adding an "index" to each process.

#include <stdio.h>
int main()
{

    int index = 0;
    if (fork()==0)
    index++;
    if (fork()==0)
    index++;
    wait(0);
    if (fork()==0)
    index++;
    wait(0); 
    printf("%d\n",index);
}

And this prints out 21312021

After commenting the wait(0)'s out, so the code is:

#include <stdio.h>
int main()
{

    int index = 0;
    if (fork()==0)
    index++;
    if (fork()==0)
    index++;
    if (fork()==0)
    index++;
    printf("%d\n",index);
}

It prints out 0112223, so something is clearly different. Why are the results different?


Solution

  • I can't see your image, but here's one that should exactly reflect the runtime behavior of this program. Adding explicit exit(0) calls helps a bit with the understanding:

    fork() ----------------------------,
      |                                |
    fork() -----,                    fork() -------,
      |         |                      |           |
      |       wait(0)                  |         wait(0)
      |         |                      |           |
      |       fork()------,            |         fork() ------, 
      |         |         |            |           |          |
      |         |       wait(0)        |           |        wait(0)
      |         |         |            |           |          |
      |         |       exit(0)        |           |        exit(0)
      |         |         |            |           |          | 
      |       wait(0) <---´            |         wait(0) <----´
      |         |                      |           |
      |       exit(0)                  |         exit(0)
      |         |                      |           |
      |         |                    wait(0) <-----´
      |         |                      |
      |         |                    fork() -------,
      |         |                      |           |
      |         |                      |         wait(0)
      |         |                      |           |
      |         |                      |         exit(0)
      |         |                      |           |
      |         |                    wait(0) <-----´
      |         |                      |
      |         |                    exit(0)
      |         |                      |
    wait(0) <---+----------------------´
      |
    fork()------,
      |         |
      |       wait(0)
      |         |
      |       exit(0)
      |         |
    wait(0) <---´
      |
    exit(0)
    

    here, each child process is drawn to the right of the parent process. Each wait(0) will wait for those lines that emerged from a fork() above.

    One thing can't be shown exactly: the first process at its first wait() is in a position where 2 child processes are running, so it will wait for whichever finishes first. The + in my picture is to be understood as an either or (and I can't think of a better way to show this graphically).