这个fork()是如何工作的

时间:2013-12-05 18:43:55

标签: c++ c linux

你能告诉我,为什么输出这个程序: 1 2 2 五 五 3 4 五 4 五 3 4 五 4 5

快速解释为什么会这样?感谢

main()
{
    printf("1\n");
    fork();
    printf("2\n");
    if(fork()==0)
    {
        printf("3\n");
        fork();
        printf("4\n");
    }
    printf("5\n");
}

7 个答案:

答案 0 :(得分:13)

假设没有调用fork失败,程序的输出应该被认为是这样的:

1
2     2
  3     3
  4 4   4 4
5 5 5 5 5 5

每列代表一个进程的输出。它们都以一些随机顺序序列化到stdout,仅 以下约束:在一列中,每个字符都不能出现在它上面的字符之前;每列中最上面的字符不能出现在它上面和左边的字符之前。

请注意,现在您的程序依赖于C库,注意到stdout是终端,因此将其设置为行缓冲。如果您运行程序,stdout重定向到文件或管道,您可能会得到相当不同的输出,例如。

$ ./a.out | tr '\n' ' '
1 2 5 1 2 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5

...因为在这种情况下,所有输出都被缓冲,直到从main返回,并且缓冲区被复制到每个子进程中。添加

setvbuf(stdout, 0, _IONBF, 0);
在第一个printf语句之前

将阻止输出的重复。 (在这种情况下,您可以改为使用_IOLBF,但_IONBF对于此类代码更安全。)

答案 1 :(得分:4)

以图形方式显示会更容易,但每次调用fork()时,您都会有另一个进程继续执行相同的代码。所以:

进程1(原始进程):打印1,然后创建进程2,打印2,然后创建进程3但不返回0,并打印5。

处理2:打印2,然后创建处理4但不返回0,并打印5。

过程3:打印3,然后创建过程5,打印4,打印5

过程4:打印3,然后创建过程6,打印4,打印5

过程5:打印4,打印5

过程6:打印4,打印5

但是他们都在相似的时间内发生,所以为什么你得到所有这些数字。

希望有所帮助。第一次回答!

答案 2 :(得分:3)

参见fedora中的某些味道假设首先执行的机会然后是孩子但是在其他像ubuntu孩子那样获得第一选择的基础上你会看到输出。与此范围内的printf函数无关但我们可以预测方法体在此处执行的次数我附加一个图像可能对您有帮助。  enter image description here

这里1只打印一个进程。执行第一个fork之后,两个不同的进程每个都有fork但在if语句中。所以再次创建两个进程,但只有一个将有机会进入if主体。 fork将再次执行,然后将再次生成新进程。公式是进程总数= 2 * n。其中n是函数内fork()方法的数量。所以总共六种方法将有一些条件来打印任何数字,如2,3,4但所有5是共同的,所以5将打印六次。   可能是我的帖子对你有帮助 谢谢 asif aftab

答案 3 :(得分:1)

因为你并不总是测试fork()来电结果。零结果路径将保留为父进程,而else部分将作为子进程执行。因为您没有测试在fork();调用之后的每个代码都将在两个进程中重复(并执行)。

答案 4 :(得分:0)

由于输出缓冲区的执行顺序和继承性,输出不是确定性的,一种确定性的方法是

#include <stdlib.h>
#include <stdio.h>

main()
{
  printf("1\n");
  fflush(stdout);
  if (fork()) wait(0);
  printf("2\n");
  fflush(stdout);
  if(fork()==0)
    {
      printf("3\n");
      fflush(stdout);
      if (fork()) wait(0);
      printf("4\n");
    } else wait();
  printf("5\n");
}

答案 5 :(得分:0)

使用fork()我们创建一个子进程,并且没有父进程或子进程的执行模式保证,如here所述。

如果你想要一个执行模式,最好检查fork()为父 [pid不为0] 或子 [pid为0] 并使其中任何一个进入休眠状态,以便调度程序将另一个执行。

您可以找到更多信息here

答案 6 :(得分:-2)

Micheal,我需要看看fork()方法中的代码才能确定,但​​是因为它是打印数字的额外数字,我能想到的唯一可能的解释是你的fork()方法可能有自己的打印方法。

罗宾