Reputation: 57
I have the following piece of code, and I want to explain the behavior of the fork() calls in this code, break condition is given as a command line argument.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int i = 0;
char *ptr;
int x = strtol(argv[1], &ptr, 10);
while (fork())
{
if (i == x)
{
break;
}
printf("PID: %d, PPID: %d, i = %d\n", getpid(), getppid(), i++);
}
return 0;
}
This is the output when 1 is given as the command line argument
PID: 684067, PPID: 14913, i = 0
PID: 684067, PPID: 14913, i = 0
What I thought should have happened was that the fork()
call would be executed once, creating a child and parent process, returning a non-zero process id to parent and a zero to the child.
A zero value should be interpreted as false, and only the parent process would proceed printing once, then incrementing the value of i to 1 and then repeating again creating another child process, which will again not enter the loop and as i = 1
this time it would break out of the loop, then why am I seeing 2 printed lines instead of just 1?
The output for higher values of i is even more puzzling but predictably prints i*(i+3)/2 lines.
Can anyone explain the flaw in my assumption?
Upvotes: 1
Views: 126
Reputation: 126526
The duplicated message you see comes from stdio buffering, and the fact that printf
does not actually print by default -- it just puts some stuff into a buffer that will be printed later, when the buffer is flushed (whicha happens when the process exits, if not before from an explicit flush or the buffer filling up).
Most importantly, when you fork a child, the child gets a copy of all the parent state -- including all the stdio buffers. So if there is any un-flushed data in a stdio buffer, that will get duplicated and (eventually) written twice -- once by the parent and once by the child.
You can avoid this by putting an explicit fflush(stdout);
after the printf
.
Complicating this is the fact that stdio also supports something called "line buffered mode", in which it will automatically flush a FILE every time a newline is written. On some systems this is set by default on stdout, but not others (it is implementation defined). You can take advantage of this by explicitly setting line-buffered mode on stdout with setlinebuf(stdout);
in the beginning of your main function.
Upvotes: 4