Daniel Anthony
Daniel Anthony

Reputation: 63

Forking WITHOUT waiting

I am unsure if I am correctly going about this, I am trying to create 7 processes total via...

void err_sys(const char* x)
{
   perror(x);
   exit(1);
}


for(i = 1; i < 7; i++){
  switch(parent = fork()){
      case -1:
         err_sys("fork error");
      case 0:       //child
         printf("I'm the child, number %d(%d)\n", i, getpid());
         break;
      default:      //parent
         printf("I'm the parent(%d)\n", getpid());
         break;
  }
    if(parent)
       break;        //loop break
}

When I run it with prog | cat > file I get 6 outputs of "I am the parent", followed with various amounts of children each. However, there are 6 children made with unique pids. The other parent pids, other than the first match a child pid. Is this just some problem that comes with output due to forking?

Upvotes: 4

Views: 424

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 754940

Your code is not incorrect a priori; it does what it does. The issue is 'does it do what you want it to do', and that is not clear because you've not clearly stated what you are trying to do.

One reason you get 6 processes is that you have a loop:

for (i = 1; i < 7; i++)

This counts 1, 2, 3, 4, 5, 6 and stops. You need to use one of two idioms:

for (i = 0; i < 7; i++)      // Idiomatic C
for (i = 1; i <= 7; i++)     // Less idiomatic C

Assuming that err_sys() does not return when called (if it did, you'd need a break; after it), then:

  1. The process forks. If the fork fails, the process exits via err_sys().
  2. If the process is the child (so the misnamed variable parent is set to 0), then the code prints "I'm the child" and then leaves the switch, and iterates around the loop again.
  3. If the process is the parent (so the misnamed variable parent is set to a non-zero value), it prints "I'm the parent" and then leaves both the switch and the loop.

Only the child from the first fork gets to re-execute the loop. However, each child except the last gets to identify itself as the parent on the next iteration of the loop.

Buffered I/O

Note that buffered I/O complicates things. If the output of the program is written to the terminal, you will get line buffered output by default. Each newline causes the data to be written to the terminal. However, when the output goes to a pipe, it is fully buffered; the data only gets written to the terminal when the buffer is full, or the process is exiting (or closes standard output for some other reason). Thus, when the output goes to a pipe, the first child has the output from just its operations, but the second child has the data printed, but not flushed, by the first child in its buffer as well as what it wrote. The third child has 3 process's worth of output, and so on.

You could add fflush(0) or fflush(stdout) after the print statements (or just after the end of the switch, before the if) and see what a difference it makes. You can also run the code without redirecting to a pipe and see what a difference that makes.

Upvotes: 3

Related Questions