What is the output of the following program?
// fork.cpp
#include <cstdio>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
int x = 1;
while (x <= 100) {
if (fork() != 0)
break;
printf("%d\n", x);
x = x+1;
}
waitpid(-1, &x, 0);
return 0;
}
Let us say I run the program as
$ ./fork
How about
$ ./fork > file.txt
Think hard before actually running the program ... the output had me stumped for a while until I realized I was wrong!
Feel free to discuss the solution in comments.
Update:
Time for Solution. So I assume that the output for the first case is clear. If not Rob explains it nicely in the comments below. What happens when we redirect the output to a file?
printf() is a C library function that uses buffering on top of the system call write() to optimize the number of expensive calls to the kernel. The C library would be dumb if it made a call to the kernel for every character output. So what is the size of the buffer? It depends ... If the output file descriptor is a terminal then it is line buffered, that is, the buffer is flushed after a new line is seen. However if the output is being sent to a file, then it is block buffered that is the size of block transfers between disk and main memory. So once we redirect it to the file the '\n' in the printf() call does not flush the buffer. Where is the buffer located ... In the process's address space of course. On invoking fork, the child process receives a copy of the parent process's address space. This includes the partially filled buffer containing the output of printf(). Now this child process calls printf() and appends to this buffer. Before exiting all buffers are flushed so the child process sends its own output appended to its' parent's output. Voila we have the output of the parent process appearing twice in the output file. This effect is chained across forks ... !
One must not depend on this buffering to implement any functionality in a program though. However flushing stdio buffers before a fork could be a harmless (and often beneficial) addition to your code!
Update:
Time for Solution. So I assume that the output for the first case is clear. If not Rob explains it nicely in the comments below. What happens when we redirect the output to a file?
printf() is a C library function that uses buffering on top of the system call write() to optimize the number of expensive calls to the kernel. The C library would be dumb if it made a call to the kernel for every character output. So what is the size of the buffer? It depends ... If the output file descriptor is a terminal then it is line buffered, that is, the buffer is flushed after a new line is seen. However if the output is being sent to a file, then it is block buffered that is the size of block transfers between disk and main memory. So once we redirect it to the file the '\n' in the printf() call does not flush the buffer. Where is the buffer located ... In the process's address space of course. On invoking fork, the child process receives a copy of the parent process's address space. This includes the partially filled buffer containing the output of printf(). Now this child process calls printf() and appends to this buffer. Before exiting all buffers are flushed so the child process sends its own output appended to its' parent's output. Voila we have the output of the parent process appearing twice in the output file. This effect is chained across forks ... !
One must not depend on this buffering to implement any functionality in a program though. However flushing stdio buffers before a fork could be a harmless (and often beneficial) addition to your code!