在 C 中使用 printf() 和 fork() 重复输出

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

我运行这个小程序要测试fork(),我看不出输出结果,程序代码是:

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

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

输出为:

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

不是应该只有两个输出吗,因为最后fork(),children没有什么可打印的?

我读到进程 child 将执行下一条指令,在 fork() 之后,尽管最后一个 children 似乎已经执行了 printf()说明。

程序的输出高度依赖于实现。

C 标准库对输出流应用缓冲。这意味着它会累积要写入的字符,直到缓冲区达到一定长度(或直到满足特定条件),然后一次输出所有文本。

最常见的行为是使用行缓冲,这意味着当遇到换行符(\n)时文本将被打印出来。这确实是你的例子在我的机器上发生的事情。由于您在 printf() 之前 fork(),因此有两个进程执行调用并立即打印输出,因为有一个换行符:

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

另一个 fork() 然后在两个进程中的每一个上执行,但是没有什么可以打印出来的,因为内部输出缓冲区已经被清空,所以在这种情况下没有什么值得注意的事情发生。

但是,根据您的具体实现和程序 运行、printf()(以及通常的任何 stdio 函数)的条件,可以决定应用不同的缓冲规则.

例如,当将输出通过管道传输到另一个程序或文件时,glibc 通常使用固定大小的缓冲区而不进行行缓冲。由于缓冲区未填充单个短 printf(),因此文本保留在其中以供稍后打印。当您第二次 fork() 时,每个新的 children 都会获得所述缓冲区的副本,然后在进程退出时(由它们中的每一个)打印所有文本。在我的系统上,当管道时,这是输出:

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

如果您想确保立即打印文本,您可以使用 fflush() or disable buffering of stdout with setvbuf()

示例:

  • 使用fflush():

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

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