繁体   English   中英

视觉上For循环中fork()会发生什么

[英]Visually what happens to fork() in a For Loop

我一直在试图理解fork()行为。 这次是for-loop 请注意以下代码:

#include <stdio.h>

void main()
{
   int i;

   for (i=0;i<3;i++)
   {
      fork();

      // This printf statement is for debugging purposes
      // getppid(): gets the parent process-id
      // getpid(): get child process-id

      printf("[%d] [%d] i=%d\n", getppid(), getpid(), i);
   }

   printf("[%d] [%d] hi\n", getppid(), getpid());
}

这是输出:

[6909][6936] i=0
[6909][6936] i=1
[6936][6938] i=1
[6909][6936] i=2
[6909][6936] hi
[6936][6938] i=2
[6936][6938] hi
[6938][6940] i=2
[6938][6940] hi
[1][6937] i=0
[1][6939] i=2
[1][6939] hi
[1][6937] i=1
[6937][6941] i=1
[1][6937] i=2
[1][6937] hi
[6937][6941] i=2
[6937][6941] hi
[6937][6942] i=2
[6937][6942] hi
[1][6943] i=2
[1][6943] hi

我是一个非常有视觉的人,所以我真正理解事物的唯一方法就是通过图表。 我的导师说会有8个hi语句。 我编写并运行了代码,确实有8个hi语句。 但我真的不明白。 所以我画了下面的图:

在此输入图像描述

图更新以反映评论:)

观察:

  1. 父进程(main)必须迭代循环3次。 然后调用printf
  2. 在父for循环的每次迭代中,调用fork()
  3. 在每次fork()调用之后,i递增,因此每个子函数在递增之前从i开始for循环
  4. 在每个for循环结束时,打印“hi”

这是我的问题:

  • 我的图表是否正确?
  • 为什么输出中有两个 i=0实例?
  • 在fork()之后, i每个孩子的价值是多少? 如果i值相同,那么“分叉”何时停止?
  • 总是这样的情况, 2^n - 1将是一种计算分叉儿童数量的方法吗? 那么,这里n=3 ,这意味着2^3 - 1 = 8 - 1 = 7孩子,这是正确的吗?

for循环开始,这是如何理解它的。

  1. 循环从父开始, i == 0

  2. fork() ,创建子1。

  3. 您现在有两个进程。 两者都打印i=0

  4. 循环在两个进程中重新启动,现在i == 1

  5. 父和子1 fork() ,创建子级2和3。

  6. 您现在有四个流程。 全部四个打印i=1

  7. 循环在所有四个进程中重新启动,现在i == 2

  8. 父母和孩子1到3都是fork() ,创建4到7岁的孩子。

  9. 你现在有八个进程。 所有八个打印i=2

  10. 循环在所有八个进程中重新启动,现在i == 3

  11. 循环在所有八个进程中终止,因为i < 3不再为真。

  12. 所有八个过程打印hi

  13. 所有八个进程终止。

所以,你得到0印刷两次, 1印刷四次, 2印刷8次, hi印刷8次。

  1. 是的,这是对的。 (见下文)
  2. 不,在调用fork 之后执行i++ ,因为这就是for循环的工作方式。
  3. 如果一切顺利,是的。 但是,请记住fork可能会失败。

关于第二个的一点解释:

for (i = 0;i < 3; i++)
{
   fork();
}

类似于:

i = 0;
while (i < 3)
{
    fork();
    i++;
}

所以i在分叉进程(父对象和子进程)中都是增量前的值。 但是,在fork()之后立即执行增量,所以在我看来,图表可以被视为正确。

逐一回答您的问题:

我的图表是否正确?

是的,基本上。 这也是一个非常好的图表。

也就是说,如果将i=0等标签解释为指向完整循环迭代,则是正确的。 然而,该图显示的是,在每个fork()之后, fork()调用之后的当前循环迭代的部分也由分叉的子进程执行。

为什么输出中有两个i=0实例?

因为fork() printf()之后有printf() ,所以它由父进程和刚分叉的子进程执行。 如果在fork() printf()之前移动printf() ,它将仅由父项执行(因为子进程尚不存在)。

fork()之后, i每个孩子的价值是多少? 如果i值相同,那么“分叉”何时停止?

fork()不会更改i的值,因此子进程看到的值与其父进程相同。

关于fork()的要记住的是它被调用一次,但它返回两次 - 一次在父进程中,一次在新克隆的子进程中。

有关更简单的示例,请考虑以下代码:

printf("This will be printed once.\n");
fork();
printf("This will be printed twice.\n");
fork();
printf("This will be printed four times.\n");
fork();
printf("This will be printed eight times.\n");

fork()创建的子进程是其父级的(几乎)精确克隆,因此,从它自己的角度来看,它“记住”作为其父级,继承所有父进程的状态(包括所有变量值,调用)堆栈和正在执行的指令)。 唯一的直接差异(除了系统元数据,例如getpid()返回的进程ID)是fork()的返回值,它在子进程中为零但非零(实际上是子进程的ID) )在父母。

总是这样的情况, 2^n - 1将是一种计算分叉儿童数量的方法吗? 那么,这里n=3 ,这意味着2^3 - 1 = 8 - 1 = 7孩子,这是正确的吗?

执行fork()每个进程都会变成两个进程(除非在异常错误条件下, fork()可能会失败)。 如果父和子继续执行相同的代码(即他们不检查fork()的返回值,或者他们自己的进程ID,并根据它分支到不同的代码路径),那么每个后续的fork将使数字加倍进程 所以,是的,在三把叉之后,你最终会得到2³= 8个进程。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM