tags:

views:

791

answers:

3

So I have this function that forks N number of child processes. However it seems to be forking more than specified. Can you tell me what I'm doing wrong? Thanks

void forkChildren(int nChildren){
    int i;
    for(i = 1; i <= nChildren; i++){
        pid = fork();
        if(pid == 0)       
            printf("I'm a child: %d PID: %d\n",i, getpid());
    }

}

In main I call:

forkChildren(5);

I am expecting the following output:

I'm a child: 1 PID: 2990
I'm a child: 2 PID: 2991
I'm a child: 3 PID: 2992
I'm a child: 4 PID: 2993
I'm a child: 5 PID: 2994

But instead I get the following:

I'm a child: 1 PID: 2990
I'm a child: 2 PID: 2991
I'm a child: 3 PID: 2992
I'm a child: 4 PID: 2993
I'm a child: 5 PID: 2994
user@computer:~/directory/$ I'm a child: 2 PID: 2999
I'm a child: 3 PID: 3000
I'm a child: 3 PID: 3001
I'm a child: 4 PID: 3002
I'm a child: 5 PID: 3003
I'm a child: 5 PID: 3004
I'm a child: 4 PID: 3005
I'm a child: 5 PID: 3006
I'm a child: 4 PID: 3007
I'm a child: 5 PID: 3008
I'm a child: 3 PID: 3011
I'm a child: 4 PID: 3012
I'm a child: 4 PID: 3010
I'm a child: 5 PID: 3013
I'm a child: 5 PID: 3014
I'm a child: 5 PID: 3015
I'm a child: 4 PID: 3018
I'm a child: 5 PID: 3019
I'm a child: 5 PID: 3020
I'm a child: 5 PID: 3021
I'm a child: 5 PID: 3023
I'm a child: 5 PID: 3025
I'm a child: 5 PID: 3024
I'm a child: 4 PID: 3022
I'm a child: 5 PID: 3026
I'm a child: 5 PID: 3027
+2  A: 

Each child process picks up and continues the loop.

In other words, child 1 is spawned and continues with iteration #2 of loop etc.

When a process is forked, a copy of the current process is made: the resulting child process continues execution after the fork() call. That's why you must take care of the return code in your logic.

jldupont
+8  A: 

The fork() call spawns a new process which begins its execution at the exact same point where the fork occurred. So, it looks like fork "returns twice"

What's happening here is that your fork() call returns twice, so both the parent and child process continue looping and spawning new processes. Each child (of both the original parent and child) then forks again, repeatedly doubling the number of processes...

Steven Schlansker
Not quite doubling. The children are still incrementing i in the loop so each of the second generation will only create four grandchildren, *not* 5. It's some form of factorial. But, other than that *minor* nitpick, good answer.
paxdiablo
+3  A: 

When you fork a process, you basically end up with two (almost) exact copies of the process and both of them will continue running.

So what's happening is that the children themselves are continuing the loop in the own process space (after they print their output) as well as the parent doing it. And, in fact, because these children are also forking, the grandchildren will also carry on from that point. I'm sure there's a formula for actually figuring out how many children you end up with (probably something like N!) but I don't have the energy to figure it out at the moment. Better to use the following solution.

The way to tell the difference between parent and child is the return value from fork.

  • If you get back a -1, you're the parent and the fork failed.
  • If you get back a zero, you're the child.
  • If you get back a positive number, you're the parent and that number is the child PID (so you can manipulate it or wait for it).

Here's some test code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void forkChildren (int nChildren) {
    int i;
    pid_t pid;
    for (i = 1; i <= nChildren; i++) {
        pid = fork();
        if (pid == -1) {
            /* error handling here, if needed */
            return;
        }
        if (pid == 0) {
            printf("I am a child: %d PID: %d\n",i, getpid());
            sleep (5);
            return;
        }
    }
}

int main (int argc, char *argv[]) {
    if (arg < 2) {
        forkChildren (2);
    } else {
        forkChildren (atoi (argv[1]));
    }
    return 0;
}

and some output to show you what's happening:

pax> forktest 5
I am a child: 1 PID: 4188
I am a child: 2 PID: 4180
I am a child: 3 PID: 5396
I am a child: 4 PID: 4316
I am a child: 5 PID: 4260

pax> _
paxdiablo
-1, fork does *not* make two copies. It makes one copy, and returns control to the caller.
Andrew Medico
Changed to clarify.
paxdiablo