在 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;
}
我运行这个小程序要测试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; }