views:

262

answers:

5
+1  Q: 

fork in a for loop

Hi,

I have a doubt in the following piece of code and its behaviour:

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

#define N 5
#define nt 1

int pm[N][2],pid[N];
int i,j,size;
char s[100];
int count=0;

int main()
{
 for(i=1;i<N;i++)
    {
      printf("\n i=%d",i);

      if(pid[i]=fork() == -1)
        {
          printf("\n fork not wrking");
          exit(1);
        }
      else if(pid[i]>0)
        {
          printf(" \n pid:%3d\n",pid[i]);
        break;
        }

    }
return 0;
}

I initially thought that the code will spawn a process and skip out of the loop. Thereby,
1 spawns 2 and skips out.
2 spawns 3 and skips out
3 spawns 4 and skips out
4 spawns 5 and skips out.

I tried executing this code and was surprised by the answer i got ( for the printf of i in the code). Here is the output

 i=1
 i=2
 i=3
 i=2
 i=4
 i=3
 i=3
 i=3
 i=4
 i=4
 i=4
 i=4
 i=4
 i=4
 i=4

Can Anyone please explain to me what is going on here. NOTE: I am working on a Solaris machine.

+1  A: 

Fork creates a duplicate process, containing everything the parent does, including file handles, etc. The only difference is the return value of fork(): the parent sees the pid, the child sees zero.

The first iteration creates the first child. Its copy of i is also 1, same as parent. The child breaks out of the loop. I get different results from you when I run it:

[wally@zf ~]$ ./a.out
i=1
i=2
i=3
i=4
wallyk
A: 

Each child process is continuing the loop with the current value of i when spawned. As a result, the first process prints an i of 1 and then spawns a child. Next, both of those process print an i of 2 and spawn a child, for a total of four processes. All four of those print an i of 3 and each spawn a new process, and finally, all 8 processes print a value of 4.

EDIT: Sorry, I overlooked the part where the parent was supposed to be exiting the loop. As for why that's not happening, it might be because the PID is stored as a signed integer but is high enough to pass the maximum signed value, making it negative. Does it work if you make this replacement?

else if(pid[i] > 0) break;

to

else if(pid[i] != 0) break;
Josh Townzen
+4  A: 

Update

You're missing a set of parentheses in your updated code. That should be if ((pid[i] = fork()) == -1) not if (pid[i] = fork() == -1)!

The latter is equivalent to if (pid[i] = (fork() == -1)) due to precedence rules. It ends up assigning 0 to pid[i] each time through the loop, so the parents think they are child processes and don't break out of the loop.


I agree with your analysis of what should happen. The parent should spawn a child and then quit, so each i=n printout should only show up once.

Are you sure you typed it in exactly as specified in your question? I ran your program (with minor modifications) and got the output you predicted:

$ cat fork.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define N 5

int main() {
    int pid[N], i;

    for(i=1;i<N;i++) /* What’s the total number of processes? */
    {
    printf("i=%d\n",i); // Output of all the is
    if((pid[i]=fork())==-1) exit(1);
    else if(pid[i] > 0) break;
    }

    return 0;
}
$ gcc -o fork fork.c
$ ./fork
i=1
i=2
$ i=3
i=4

Note that I moved the \n in the printout to the end. When you put it at the beginning of the line you end up with stdout not being flushed, so you get multiple printouts when the parent and child processes both flush their output buffers. That might be the cause of your problem. FWIW on my Mac I got each printout twice.

John Kugelman
+1, and also, your and my edits to the code are exactly the same. :-)
Alok
@John: Thank you for that last update. It works fine now. Cant believe the braces made such a big mess.. Thanks again
tomkaith13
Good catch. I think the original code posted did have the extra set of parentheses.
Kevin Gale
A: 

What flavor of Unix are you using. Is there any chance fork isn't returning an int?

In that case the pid[i] > 0 compare might fail.

Kevin Gale
@Kevin: Solaris
tomkaith13
+1  A: 

The expression

if (pid[i] = fork() == -1) {

won't do what you expect. You probably meant to say

if ((pid[i] = fork()) == -1) {
mobrule