dums
dums

Reputation: 31

fork() within a fork() within a while loop

Please consider looking at my code here. My plan is that I have a while loop. Inside that while loop I execute a for statement. After the for loop, I use fork. Now I have a parent and a child1. Inside the parent I perform another fork, giving me a parent and child2. Now my questions are:

1) why is it that when x=3, the statement "fork1 successful" prints twice?

2) for x=2, same problem occurred with x=3. It said fork 1 and fork 2 are successful but did not enter both child1 and child2. It skipped the line n=waitpid(-1, &status, 0); and just proceeded to print n, then x-- and went to x=1;

3) for x=1, I think that the outputs got really mixed up, like why was a "child1 pid=4783" printed between SENDING 1 and SENDING 2. fork 1 also printed twice again.

Please help me fix these problems. I've been reading posts but I can't seem to see similar problems. What could I have missed out? Thank you so much! Here is a snippet of my code:

while(x>0)
{
    printf("x=%d\n", x);
    for(i=0; i<3; i++)
    {
        printf("SENDING %d\n", i);
    }

    pid1=fork();
    printf("fork1 successful\n");
    if(pid1>0)
    {
        printf("RECEIVING %d\n", i);
        pid2=fork();
        if(pid2>0)
        {
            printf("fork2 successful\n");
            n=waitpid(-1, &status, 0);
            printf("%d\n", n);

            if(n==pid1) //sleep done
            {
                kill(pid2, SIGKILL);
                printf("Child1 ran. Child2 killed.\n\n");
            }

            else if(n==pid2) //scanf received               
            {
                kill(pid1, SIGKILL);
                printf("Child2 ran. Child1 killed.\n\n");
            }
        }    
        else
        {
            printf("child2 pid=%d\n", getpid());            
            scanf("%d", &y);
            exit(1);
        }
    }
    else
    {
        printf("child1 pid=%d\n", getpid());
        sleep(5);
        exit(0);
    }
x--;
}

And the following result:

x=3

SENDING 0

SENDING 1

SENDING 2

fork1 successful

RECEIVING 3

fork1 successful

child1 pid=4781

fork2 successful

child2 pid=4782

4781

Child1 ran. Child2 killed.

x=2

SENDING 0

SENDING 1

SENDING 2

fork1 successful

RECEIVING 3

fork1 successful

fork2 successful

4782

x=1

SENDING 0

SENDING 1

child1 pid=4783

SENDING 2

fork1 successful

RECEIVING 3

child2 pid=4784

fork2 successful

child2 pid=4786

fork1 successful

child1 pid=4785

1

4784

Upvotes: 3

Views: 876

Answers (1)

Kev Bo
Kev Bo

Reputation: 172

I believe you're assuming that n=waitpid(-1, &status, 0) will pause until one of the child processes has completed. The waitpid will return following any change in any child process. If you add the variable "x" to the print statements, and also add a statement to show the status return value from waitpid, you can see that on the second loop where x=2, the waitpid statement is being triggered by the termination signal of one of the previous loop's processes. Things get messier here - as processes may preempt eachother. In your original code, you can see two child1 processes showing up for x=1.

x=3
[3] SENDING 0
[3] SENDING 1
[3] SENDING 2
[3] fork1 successful
[3] RECEIVING 3
[3] fork2 successful
[3] fork1 successful
[3] child1 pid=8166
[3] child2 pid=8167
[3] child1 exiting
[3] process ID 8166 returned status 0.[3] Child1 ran. Child2 killed.

x=2
[2] SENDING 0
[2] SENDING 1
[2] SENDING 2
[2] fork1 successful
[2] RECEIVING 3
[2] fork1 successful
[2] fork2 successful
[2] process ID 8167 returned status 9.x=1
[1] SENDING 0
[1] SENDING 1
[1] SENDING 2
[2] child1 pid=8171
[2] child2 pid=8172
[1] fork1 successful
[1] RECEIVING 3
[1] fork1 successful
[1] child1 pid=8173
[1] fork2 successful
[1] child2 pid=8174
[2] child1 exiting
[1] child1 exiting
[1] process ID 8171 returned status 0

One way to fix this would be to check the status of waitpid:

do
{
  n=waitpid(-1, &status, 0);
  printf("[%d] process ID %d returned status %d.", x, n, status);
  if (WIFEXITED(status)==0)
     printf("This is NOT an exit status, so I will keep looping....\n");
  else
     printf("\n");

 } while (WIFEXITED(status)==0);

then I believe you get the intended result:

x=3
[3] SENDING 0
[3] SENDING 1
[3] SENDING 2
[3] fork1 successful
[3] RECEIVING 3
[3] fork2 successful
[3] fork1 successful
[3] child1 pid=8267
[3] child2 pid=8268
[3] child1 exiting
[3] process ID 8267 returned status 0.
[3] Child1 ran. Child2 killed.

x=2
[2] SENDING 0
[2] SENDING 1
[2] SENDING 2
[2] fork1 successful
[2] RECEIVING 3
[2] fork2 successful
[2] process ID 8268 returned status 9.This is NOT an exit status, so I will keep looping....
[2] fork1 successful
[2] child1 pid=8270
[2] child2 pid=8271
[2] child1 exiting
[2] process ID 8270 returned status 0.
[2] Child1 ran. Child2 killed.

x=1
[1] SENDING 0
[1] SENDING 1
[1] SENDING 2
[1] fork1 successful
[1] RECEIVING 3
[1] fork1 successful
[1] child1 pid=8273
[1] fork2 successful
[1] process ID 8271 returned status 9.This is NOT an exit status, so I will keep looping....
[1] child2 pid=8274
[1] child1 exiting
[1] process ID 8273 returned status 0.
[1] Child1 ran. Child2 killed.

Upvotes: 1

Related Questions