linux中的fork()行为

我试图了解叉子,并尝试在C中关注:

#include #include  void forker() { printf("%d: A\n",(int)getpid()); fork(); wait(); printf("%d: B\n",(int)getpid()); printf("%d: C\n",(int)getpid()); fork(); wait(); printf("%d: D\n",(int)getpid()); } int main(void) { forker(); return 0; } 

当我编译并运行结果a.out时,这是我观察到的:

 > ./a.out 3560: A 3561: B 3561: C 3562: D 3561: D 3560: B 3560: C 3563: D 3560: D 

但是,当我执行以下操作时:

 > ./a.out > t.txt 

奇怪的事情发生了:

 > cat t.txt 3564: A 3565: B 3565: C 3566: D 3564: A 3565: B 3565: C 3565: D 3564: A 3564: B 3564: C 3567: D 3564: A 3564: B 3564: C 3564: D 

有人可以解释一下这种行为吗? 为什么重定向到文件时输出会有所不同?

我使用的是Ubuntu 10.10,gcc版本4.4.5。

发生这种情况的原因是数据缓冲。 在fork()时,在指向文件的情况下,你的输出还没有被刷新…所以父和子现在都有未完成的输出缓冲区。

拨打fflush(stdout); 在每个fork();之前fork(); 解决这个问题。

问题是printf的输出在发送到文件之前通过库缓冲区传递,这会导致您提到的奇怪行为。 如果在每次printf之后添加fflush(stdout) ,则输出也将在文件内正确。

你可以在这里阅读更多相关信息: http : //www.pixelbeat.org/programming/stdio_buffering/

其他答案并没有准确描述正在发生的事情,我不得不多思考一下。 因此,在第二种情况下(由于文件重定向而缓冲输出),并使用1,2,3和4而不是3564,3565,3566和3567:

  • 进程1在其内部stdout缓冲区中打印“A:1”;
  • 创建进程1 forks和进程2,此创建意味着仍未打印的内部stdout缓冲区的副本;
  • 进程1在其内部stdout缓冲区中打印“B:1”和“C:1”,进程2“B:2”和“C:2”;
  • 两个进程fork(在你的情况下1-> 4和2-> 3,但它可能是不同的),复制两个内部缓冲区;
  • 所有4个进程在其缓冲区中打印D行,然后退出。

此时,4个内部stdout缓冲区的内容为:

 - process 1: A:1 B:1 C:1 D:1 - process 2: A:1 B:2 C:2 D:2 - process 3: A:1 B:2 C:2 D:3 - process 4: A:1 B:1 C:1 D:4 
  • 最后,4个缓冲区以非确定性顺序打印。 在您的情况下,订单是3,2,4,1。

当stdout是shell或fflush() ,不会发生此行为,因为stdout缓冲区在每个fork()之前被转储,因此只复制空缓冲区。