从视觉上来看,For循环中fork()会发生什么

我一直在尝试理解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声明。 我编写并运行了代码,实际上有8个hi语句。 但是我真的不明白。 所以我画了下图:

在这里输入图像说明

图更新,以反映评论:)

观察:

  1. 父进程(main)必须迭代循环3次。 然后printf被调用
  2. 在父循环的每次迭代中,调用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() ,创build子项1。

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

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

  5. 父母和孩子1 fork() ,创build孩子2和3。

  6. 你现在有四个进程。 所有四个打印i=1

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

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

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

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

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

  12. 所有八个进程打印hi

  13. 所有八个进程终止。

所以你打印两次,一次打印四次, 2打印八次,打印八次。

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

第二个小解释:

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

类似于:

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

所以i在分叉进程(父母和孩子)是增量前的值。 然而, fork()之后立即执行增量,所以在我看来,图可以被视为正确的。

要一一解答你的问题:

我的图是否正确?

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

也就是说,如果将i=0等标签解释为指全循环迭代,那么这是正确的。 然而,图表没有显示的是,在每个fork()之后, fork()调用之后的当前循环迭代的部分也由分叉subprocess执行。

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

因为在fork() printf()后面有printf() ,所以它由父进程和刚分叉的subprocess执行。 如果在fork() printf()之前移动printf() ,则只会由父级执行(因为subprocess尚不存在)。

fork()之后, i将什么值传递给每个孩子? 如果i继续使用相同的值,那么“分叉”何时停止?

i的值没有被fork()改变,所以subprocess和父进程有相同的值。

关于fork()一点是它被调用一次,但是它会返回两次,一次在父进程中,一次在新克隆的subprocess中。

更简单的例子,请考虑以下代码:

 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()创build的subprocess是其父进程的一个(几乎)精确的克隆,因此,从它自己的angular度来看,它“记住”它的父进程,inheritance所有父进程的状态(包括所有variables值,堆栈和正在执行的指令)。 唯一的直接差别(除了系统元数据,如getpid()返回的进程ID)是fork()的返回值,在subprocess中它将为零,但非零(实际上是subprocess的ID )在父母。

2^n - 1是否会成为计算分叉子女数量的一种方法? 那么这里n=3 ,意思是2^3 - 1 = 8 - 1 = 7孩子,这是否正确?

执行fork()每个进程都会变成两个进程(除非在不正常的错误情况下fork()可能会失败)。 如果父母和孩子继续执行相同的代码(即,他们不检查fork()的返回值或他们自己的进程ID,并基于它分支到不同的代码path),那么每个后续的fork将会使数字加倍的过程。 所以,是的,三叉之后,最终会有2 3 = 8个进程。