C函数中fork函数的位置及其对输出的影响

时间:2015-12-01 18:25:09

标签: c linux

我正在学习C语言中的fork函数,并且正在学习过去的考试,并且遇到了一个非常有趣的问题。

请参阅以下代码:

int main(void) {

printf("Hello ");
fork();
printf("Hello ");
fork();
printf("Hello \n");

pause();
return 0;
}

结果输出

Hello Hello Hello 
Hello Hello Hello 
Hello Hello Hello 
Hello Hello Hello 

如果我将代码改为

    fork();
    fork();
    printf("Hello ");
    printf("Hello ");
    printf("Hello \n");

输出结果仍然相同。 为什么fork函数的位置对输出本身没有影响。 fork在执行之前是否等待所有printf()完成?这应该解释输出,因为第一次printf()将打印出Hello的第一行,然后它将被分叉并且将打印另外1行Hello。然后第二个分叉将分叉前两行并生成另外两行Hello。

然而,问题只是稍微改变了代码,整个输出发生了巨大的变化。

printf("Hello \n");
fork();
printf("Hello ");
fork();
printf("Hello \n");

这导致输出

Hello 
Hello Hello 
Hello Hello 
Hello Hello 
Hello Hello

我不明白为什么只添加一个' \ n'将产生5行输出而不是4。这次,如果我像以前一样将fork函数的位置更改为顶部,输出也会改变。看来fork函数没有效果这次是printf的第一行。有人可以向我解释一下fork函数输出的确切内容吗?

2 个答案:

答案 0 :(得分:4)

问题不在于顺序,这是无关紧要的,因为我们正在处理fork()并且您没有关于两个同时线程的并发性的保证。

问题是程序根据程序的语义打印了一个不正确的Hello。如果你考虑一下

  • 第一个printf仅由父进程执行
  • 第二个printf由父进程和子进程执行
  • 第三个printf由父进程,子进程以及父母和第一个孩子的两个子女执行

这会产生总共7个printf,而你得到12或11.问题在于,当你在{{fork()内部调用某个内容时,输出是按行缓存的。 1}}缓冲然后发生奇怪的事情。如果您将代码更改为:

stdout

您将获得:

#include <unistd.h>

int main(void) {
  printf("(1:%u)\n", getpid());
  fork();
  printf("(2:%u)\n", getpid());
  fork();
  printf("(3:%u)\n", getpid());
  pause();
  return 0;
}

这是正确的,因为现在我们在cuboid:Dev jack$ ./a.out (1:4307) (2:4307) (3:4307) (2:4308) (3:4309) (3:4308) (3:4310) 的每次调用中强制刷新(\n),并且pid对应于我们之前看到的内容:1,2,4次调用。< / p>

如果在代码中调用printf之前强行刷新,例如:

fork()

您将获得:

int main(void) {
  printf("1Hello ");
  fflush(stdout);
  fork();
  printf("2Hello ");
  fflush(stdout);
  fork();
  printf("3Hello \n");
  pause();
  return 0;
}

产生相同的正确结果,您可以看到父进程通过所有3行,第一个子进行第2和第3次,而最后两个子进程仅通过最后一个。

答案 1 :(得分:2)

您使用printf()遇到了缓冲I / O的特殊副作用。通常,如果有换行符,printf()实际上只会将文本打印到控制台,否则它将在内部缓冲该文本,等待下一个换行符。

在你的情况下发生的事情是前两个printf()调用没有进入控制台而是保持缓冲状态。分叉程序时,内部缓冲区也是分叉的 - 意味着它的内容也被复制到新程序中。因此,当他们做最后的printf()时,该程序的所有副本都有“你好”的三份副本。

如果你用fflush(0)强制文本输出到控制台,你应该得到你期望的行为(有点):

int main(void) {
    printf("Hello ");   fflush(0);
    fork();
    printf("Hello ");   fflush(0);
    fork();
    printf("Hello \n"); fflush(0);
    pause();
    return 0;
}

导致

Hello Hello Hello 
Hello Hello 
Hello 
Hello 

Hello Hello Hello Hello 
Hello 
Hello 
Hello 

你也可以得到其他组合......

您仍然在程序的不同副本之间进行竞赛,以查看谁先完成并打印相对于其他人的换行符。