I was trying to use the fork()
function, but I'm getting some strange behavior. Part (not all) of the main function of the parent process is seemingly run right after fork()
is called, but only if the output of the executable is piped somewhere on the command line.
I noticed this on Mac OS Mojave, but I have tested the same code on Ubuntu 18.04, which exhibits the same behavior. I have no idea why this is happening.
Here is the test code in the file fork.c
:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
pid_t child_pid;
printf("Beginning of main for process %d\n", getpid());
if ((child_pid = fork())) {
printf("Forked process %d\n", child_pid);
} else {
printf("Beginning of forked process %d\n", getpid());
}
}
And here is a shell session using this code:
$ cc fork.c
$ ./a.out
Beginning of main for process 98373
Forked process 98374
Beginning of forked process 98374
$ ./a.out | cat
Beginning of main for process 98378
Forked process 98380
Beginning of main for process 98378
Beginning of forked process 98380
As you can see above, the statement at the beginning of main()
is executed twice in the parent process if the output is piped somewhere.
This has to do with I/O buffering.
The console is line buffered by default, so if your output string ends in a newline and you don't redirect, the output is flushed right away. But when you redirect stdout a newline doesn't flush the buffer. So when you fork both the parent and the child have a line of text in the output buffer so the both print the first line.
You can fix this by explicitly flushing the buffer with fflush
.
printf("Beginning of main for process %d\n", getpid());
flush(stdout);