Duplicated output using printf() and fork() in C

The output of your program is highly implementation dependent.

The C standard library applies buffering to the output stream. This means that it accumulates characters to write until the buffer reaches a certain length (or until a certain condition is met), and then outputs all the text at once.

The most common behavior is to use line buffering, which means that the text will be printed out when a newline character (\n) is encountered. This is indeed what happens on my machine with your example. Since you fork() before the printf(), two processes execute the call and the output is immediately printed since there is a newline:

$ ./prog
Inside i= 0
Inside i= 0

The other fork() is then executed on each of the two processes, but there’s nothing more to print out, since the internal output buffer has already been emptied, so nothing noticeable happens in this case.

However, depending on your specific implementation and the conditions in which the program is run, printf() (and in general any stdio function) could decide to apply different buffering rules.

For example, when piping the output to another program or to a file, glibc usually uses a fixed size buffer and does not do line buffering. Since the buffer is not filled with a single short printf(), the text is retained inside it to be printed later. When you fork() a second time, each of the new children gets a copy of said buffer, and all the text is then printed (by each one of them) when the process exits. On my system, when piping, this is the output:

$ ./prog | cat
Inside i= 0
Inside i= 0
Inside i= 0
Inside i= 0

If you want to make sure the text is printed right away, you can either use fflush() or disable buffering of stdout with setvbuf().

Examples:

  • Using fflush():

    void create()
    {
        fork();
        printf("Inside i= %d \n", i);
        fflush(stdout);
        i = i + 1;
        fork();
    }
    
  • Using setvbuf():

    int main()
    {
        setvbuf(stdout, NULL, _IONBF, 0);
        create();  
        return 0;
    }
    

Leave a Comment