考虑以下代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
int i;
for(i = 0; i < 2; i++)
{
fork();
printf(".");
}
return 0;
}
该程序输出8个点。怎么可能呢?不应该有6个点吗?
答案 0 :(得分:243)
fork()
原语经常延伸想象力。在您了解它之前,您应该在纸上找出每项操作的内容并说明进程数。不要忘记fork()创建了一个近乎完美的当前进程副本。最重要的区别(对于大多数用途)是fork()
的父级和子级之间的返回值不同。 (由于此代码忽略了返回值,因此没有区别。)
所以,首先,有一个过程。这创建了第二个进程,两个进程都打印了一个点和循环。在第二次迭代中,每个都创建另一个副本,因此有四个进程打印一个点,然后退出。因此,我们可以像您期望的那样轻松地占据六个点。
然而,printf()
真正做的是缓冲其输出。因此,只有两个进程的第一个点在写入时不会出现。这些点保留在缓冲区中 - 在fork()处重复。直到该过程即将退出,才会出现缓冲点。打印缓冲点的四个过程加上新的点可以得到8个点。
如果您想避免这种行为,请在fflush(stdout);
之后致电printf()
。
答案 1 :(得分:70)
您在输出流中有未提交的缓冲区。 stdout是行缓冲的,缓冲区与进程的其余部分一起复制。程序终止时,未提交的缓冲区被写入两次(每个进程一次)。两者都使用
printf("a\n");
和
printf("a "); fflush(stdout);
不要表现出问题。
在第一个示例中,您创建了四个进程,其输出流缓冲区中每两个点都有一个。当每个流终止时,它会刷新缓冲区,产生8个点。
答案 2 :(得分:2)
Process_1:缓冲文本= 1点
Process_2(由Process_1创建):缓冲文本= 1点
<=> 当i = 1 时Process_3(由Process_1创建):从Process_1继承1个缓冲点并自行打印1个点。 Process_3总共打印2个点。
Process_4(由Process_2创建):从Process_2继承1个缓冲点并自行打印1个点。总共Process_4打印2个点。
Process_1:打印2个点(i = 0时为一个缓冲点,i = 1时为另一个点)
Process_2:打印2个点(i = 0时为一个缓冲点,i = 1时为另一个点)
最终输出:8点。 :)