Leonard Mohr
Leonard Mohr

Reputation: 59

Processes not executing in expected order; fork() and waitpid()

I wrote a program that calls fork() two times, generating three children and a parent.

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

int main() {
    int child1 = fork();
    int child2 = fork();

    // Check for error
    if (child1 < 0 || child2 < 0) {
        fprintf(stderr, "A fork failed :(\n");
        exit(1);
    }

    // Parent Process
    if (child1 > 0 && child2 > 0) {
        waitpid(child1, NULL, 0);
        waitpid(child2, NULL, 0);
        printf("I'm the parent\n");
    }
    // Child B -- CONFUSION AREA --
    else if (child1 > 0 && child2 == 0) {
        waitpid(child1, NULL, 0); // Not waiting for process to finish
        printf("I'm child B\n");
    }
    // Child A
    else if (child1 == 0 && child2 > 0) {
        waitpid(child2, NULL, 0);
        printf("I'm child A\n");
    }
    // Child C
    else if (child1 == 0 && child2 == 0) {            
        printf("I'm child C\n");
    }

    return 0;
}

I'm trying to print out

I'm child C
I'm child A
I'm child B
I'm the parent

but instead, the program prints out

I'm child B
I'm child C
I'm child A
I'm the parent

I'm confused why child B isn't waiting for child1process to finish?

I drew a process tree to try and understand what is going on, and my understanding is that it looks like:

/*

         Parent (15543)
         child1 = 15544;
         child2 = 15545
           /       \
          /         \
         /           \
        A (15544)     B (15545)
     child1 = 0;      child1 = 15544;
     child2 = 15546;  child2 = 0;
        /
       /
      /
     C (15546)
     child1 = 0;
     child2 = 0;


*/

Upvotes: 0

Views: 143

Answers (2)

Luis Colorado
Luis Colorado

Reputation: 12668

When you execute the first fork(), both processes (parent and child) go to the second fork() and generate the two other processes you see in the tree. This is the reason you see a grandchild in the output. You think there are only two forks executed, so two children are expected, but you have not realized that the second fork() is actually executed by two processes: the parent and the child of the first fork() call.

BTW, the kernel schedules the processes in any order, so you can expect different order in the output lines. Child B cannot waitpid() as it has not started any child (it is the child B in your tree, It has the pid that the parent got for child A, but child A is not its child, so waitpid() gives you an error, that you don't examine, and so the printing is done) You assumed it was a parent because one of the child variables was > 0, but he inherited that variable initialized from its parent, as it didn't execute a fork() call.

Upvotes: 1

Willis Hershey
Willis Hershey

Reputation: 1574

When child B calls waitpid() the call fails and returns -1 because the parent is already waiting on child A, and you can't reap a child process twice.

For the behavior you want, you may be better off using inter-process semaphores to synchronize your process execution. Try including semaphore.h and take a look at the documentation for sem_init().

Upvotes: 1

Related Questions