Home > other >  What is fork() doing here?
What is fork() doing here?

Time:01-17

So I am trying to figure out what this code is doing:

int k = 5;
 if(fork() == fork())   k; else --k;
 printf("%d\n", k);

The thing that bothers me is that I receive different outputs:

4
4
4
6
4
4
4
4
4
6
4
4
4
6
4
6
4
4

I have added a PID detector so I see the ids of all the processes:

int main ()
{
   int k = 5;
    if(fork() == fork())   k; else --k;
    printf("%d\n", k);
    int pid;
    pid = fork();
    if(pid == 0)
    {
         printf("\n Process id : %d",getpid());
         printf("\n Parrent process id : %d\n" ,getppid());
    }

    return 0;
}

But sometimes I get the output:

Process id : 9472
 Parrent process id : 1413

 Process id : 9474
 Parrent process id : 1413

 Process id : 9471
 Parrent process id : 1413

 Process id : 9473
 Parrent process id : 1413

or:

 Process id : 9557
 Parrent process id : 1413

 Process id : 9556
 Parrent process id : 1413

 Process id : 9558
 Parrent process id : 9554

 Process id : 9559
 Parrent process id : 9553

Please make me understand what is happening here.

CodePudding user response:

I expanded your original code to wait for the children so that you'll be sure to get all output and added some more output.

You have two forks so there will be four processes in total.

Only in one of these processes will fork() == fork() be true. It's when the first called of those two fork()s returns to a child process and the next fork() is called and also returns to a child process.

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

const char *foo(pid_t a, pid_t b) {
    if (a == b) return "child,child";
    if (a && b) return "parent,parent";
    if (a) return "parent,child";
    return "child,parent";
}

int main() {
    int k = 5;
    pid_t p1, p2;

    if ((p1 = fork()) == (p2 = fork())) {
          k;
    } else {
        --k;
    }

    printf("%d %s\tppid=%d  pid=%d\n", k, foo(p1, p2), getppid(), getpid());

    int wstatus;
    if (p1) wait(&wstatus);
    if (p2) wait(&wstatus);
}

Example output. Note that the order may change since all the processes run at the same time.

6 child,child   ppid=2  pid=4
4 parent,child  ppid=1  pid=3
4 child,parent  ppid=1  pid=2
4 parent,parent ppid=0  pid=1

Here the first process, 1, creates 2 and 3 and it is in the case where 2 was created that we got fork() == fork().

    1
   / \
  2   3
 /
4

CodePudding user response:

The thing that bothers me is that I receive different outputs:

The code presented unconditionally fork()s twice. After the first fork succeeds, there are two processes where originally there was one. Both execute the second fork, so, provided that all the fork calls succeed, there are eventually four processes.

On success, fork() returns the child PID to the original process and 0 to the child. On failure, it returns -1 to the parent (and there is no child). If in fact both forks succeed then all the resulting processes' PIDs will differ, so the only case in which fork() == fork() will evaluate to true is in the child of the first child, in which both fork() calls will have returned 0. In that process alone, k will be incremented; in the other processes it will be decremented.

The processes do not share memory, so the increments and decrements are reflected separately in the various processes' separate copies of k. No control having been exerted over the order in which the various processes run, they may, in principle, print their values of k in any order. That covers three of the observed outputs.

But what about the cases where only three values of k are printed? The most likely explanation for these is that the first fork() succeeds, but in one of the resulting processes the second one fails, returning -1. If it is in the original process that the fork() failure occurs then the successful instance of the second fork() will still produce one process in which fork() == fork() evaluates to true. On the other hand, if it is in the first child that the fork failure occurs then there will be no process in fork() == fork() evaluates to true. This would explain the two three-output results.


As far as the PIDs and PPIDs go, one thing that seems to be throwing you is the effect of some of the processes' parent processes terminating. A process other than the initial one always has a living process as its parent. If the original parent of process P terminates before P itself does, then a different parent is assigned; on a POSIX-conforming system, that will be process 1.

Because your program does nothing to ensure that the parent processes outlive their children, you are sometimes seeing the effects of some of the original parents terminating before their children. This explains the variations in the patterns of PPIDs. However, you seem to be running your program in an environment (presumably some kind of container) that does not conform to POSIX with regard to details of the assignment of the new parent, which is somewhat disguising the source of that issue.

  •  Tags:  
  • Related