Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
656 views
in Technique[技术] by (71.8m points)

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

I run this small program to test fork(), and I can't figure out the output, the program's code is:

#include <stdio.h> 
#include <sys/types.h> 
#include <unistd.h> 

int i = 0;
void create()
{
    fork();
    printf("Inside i= %d 
", i);
    i = i + 1;
    fork();
}
int main()
{
    create();  
    return 0;
}

The output is:

Inside i= 0 
Inside i= 0 
Inside i= 0 
Inside i= 0 

Aren't there supposed to be just two outputs, because in the last fork(), the children has nothing to print out?

I've read that the process child will execute the next instruction, after the fork(), though the last children seems to have executed the printf() instruction.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 ( ) 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 
    ", i);
        fflush(stdout);
        i = i + 1;
        fork();
    }
    
  • Using setvbuf():

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...