C语言 视觉上 fork() 在 For 循环中会发生什么
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26793402/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Visually what happens to fork() in a For Loop
提问by lucidgold
I have been trying to understand fork()behavior. This time in a for-loop. Observe the following code:
我一直在努力理解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());
}
Here is the output:
这是输出:
[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
I am a very visual person, and so the only way for me to truly understand things is by diagramming. My instructor said there would be 8 histatements. I wrote and ran the code, and indeed there were 8 histatements. But I really didn't understand it. So I drew the following diagram:
我是一个非常视觉化的人,所以我真正理解事物的唯一方法是通过图表。我的导师说会有 8 个hi语句。我编写并运行了代码,确实有 8 个hi语句。但我真的没看懂。于是我画了下图:


Diagram updated to reflect comments :)
图表更新以反映评论:)
Observations:
观察:
- Parent process (main) must iterate the loop 3 times. Then printf is called
- On each iteration of parent for-loop a fork() is called
- After each fork() call, i is incremented, and so every child starts a for-loop from i before it is incremented
- At the end of each for-loop, "hi" is printed
- 父进程(主进程)必须迭代循环 3 次。然后 printf 被调用
- 在父 for 循环的每次迭代中,都会调用 fork()
- 在每次 fork() 调用之后, i 递增,因此每个孩子在递增之前从 i 开始一个 for 循环
- 在每个 for 循环结束时,打印“hi”
Here are my questions:
以下是我的问题:
- Is my diagram correct?
- Why are there twoinstances of
i=0in the output? - What value of
iis carried over to each child after the fork()? If the same value ofiis carried over, then when does the "forking" stop? - Is it always the case that
2^n - 1would be a way to count the number of children that are forked? So, heren=3, which means2^3 - 1 = 8 - 1 = 7children, which is correct?
- 我的图表正确吗?
- 为什么输出中有两个实例
i=0? i在 fork() 之后传递给每个孩子的值是多少?如果i结转相同的值,那么“分叉”何时停止?2^n - 1计算分叉的孩子数量的方法总是如此吗?那么,在这里n=3,这意味着2^3 - 1 = 8 - 1 = 7孩子,哪个是正确的?
采纳答案by Crowman
Here's how to understand it, starting at the forloop.
下面是如何理解它,从for循环开始。
Loop starts in parent,
i == 0Parent
fork()s, creating child 1.You now have two processes. Both print
i=0.Loop restarts in both processes, now
i == 1.Parent and child 1
fork(), creating children 2 and 3.You now have four processes. All four print
i=1.Loop restarts in all four processes, now
i == 2.Parent and children 1 through 3 all
fork(), creating children 4 through 7.You now have eight processes. All eight print
i=2.Loop restarts in all eight processes, now
i == 3.Loop terminates in all eight processes, as
i < 3is no longer true.All eight processes print
hi.All eight processes terminate.
循环从父级开始,
i == 0父
fork()s,创建子 1。您现在有两个进程。两者都打印
i=0。循环在两个进程中重新启动,现在
i == 1。父和子 1
fork(),创建子 2 和 3。您现在有四个进程。所有四个打印
i=1。循环在所有四个进程中重新启动,现在
i == 2。父级和子级 1 到 3 所有
fork(),创建子级 4 到 7。您现在有八个进程。所有八个打印
i=2。循环在所有八个进程中重新启动,现在
i == 3。循环在所有八个进程中终止,这
i < 3不再正确。所有八个进程都打印
hi.所有八个进程都终止。
So you get 0printed two times, 1printed four times, 2printed 8 times, and hiprinted 8 times.
所以你被0打印了两次,被1打印了四次,被2打印了 8 次,然后被hi打印了 8 次。
回答by Yu Hao
- Yes, it's correct. (see below)
- No,
i++is executed afterthe call offork, because that's the way theforloop works. - If all goes successfully, yes. However, remember that
forkmay fail.
- 是的,它是正确的。(见下文)
- 不,在调用之后
i++执行,因为这是循环的工作方式。forkfor - 如果一切顺利,是的。但是,请记住这
fork可能会失败。
A little explanation on the second one:
关于第二个的一点解释:
for (i = 0;i < 3; i++)
{
fork();
}
is similar to:
类似于:
i = 0;
while (i < 3)
{
fork();
i++;
}
So iin the forked processes(both parent and child) is the value before increment. However, the increment is executed immediately after fork(), so in my opinion, the diagram could be treat as correct.
所以i在分叉进程(父进程和子进程)中是增量前的值。但是,增量是在 之后立即执行的fork(),因此在我看来,该图可以被视为正确的。
回答by Ilmari Karonen
To answer your questions one by one:
一一回答您的问题:
Is my diagram correct?
我的图表正确吗?
Yes, essentially. It's a very nice diagram, too.
是的,本质上。这也是一个非常好的图表。
That is to say, it's correct if you interpret the i=0etc. labels as referring to full loop iterations. What the diagram doesn'tshow, however, is that, after each fork(), the part of the current loop iteration after the fork()call is also executed by the forked child process.
也就是说,如果您将i=0etc. 标签解释为指代完整循环迭代是正确的。然而,图中没有显示的是,在 eachfork()之后,fork()调用之后的当前循环迭代部分也由分叉的子进程执行。
Why are there two instances of
i=0in the output?
为什么
i=0输出中有两个实例?
Because you have the printf()after the fork(), so it's executed by both the parent process and the just forked child process. If you move the printf()before the fork(), it will only be executed by the parent (since the child process doesn't exist yet).
因为你有printf()after fork(),所以它由父进程和刚刚分叉的子进程执行。如果在printf()之前移动fork(),它将仅由父进程执行(因为子进程尚不存在)。
What value of
iis carried over to each child after thefork()? If the same value ofiis carried over, then when does the "forking" stop?
i之后的每个孩子都有什么价值fork()?如果i结转相同的值,那么“分叉”何时停止?
The value of iis not changed by fork(), so the child process sees the same value as its parent.
的值i不会被 更改fork(),因此子进程看到的值与其父进程相同。
The thing to remember about fork()is that it's called once, but it returns twice — once in the parent process, and once in the newly cloned child process.
需要记住的fork()是,它被调用了一次,但它返回了两次——一次在父进程中,一次在新克隆的子进程中。
For a simpler example, consider the following code:
对于更简单的示例,请考虑以下代码:
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");
The child process created by fork()is an (almost) exact clone of its parent, and so, from its own viewpoint, it "remembers" being its parent, inheriting all of the parent process's state (including all variable values, the call stack and the instruction being executed). The only immediate difference (other than system metadata such as the process ID returned by getpid()) is the return value of fork(), which will be zero in the child process but non-zero (actually, the ID of the child process) in the parent.
创建的子进程fork()是其父进程的(几乎)完全克隆,因此,从它自己的角度来看,它“记得”是它的父进程,继承了父进程的所有状态(包括所有变量值、调用堆栈和正在执行的指令)。唯一的直接区别(除了系统元数据,例如由 返回的进程 ID getpid())是 的返回值fork(),它在子进程中为零,但在父进程中非零(实际上是子进程的 ID)。
Is it always the case that
2^n - 1would be a way to count the number of children that are forked? So, heren=3, which means2^3 - 1 = 8 - 1 = 7children, which is correct?
2^n - 1计算分叉的孩子数量的方法总是如此吗?那么,在这里n=3,这意味着2^3 - 1 = 8 - 1 = 7孩子,哪个是正确的?
Every process that executes a fork()turns into two processes (except under unusual error conditions, where fork()might fail). If the parent and child keep executing the same code (i.e. they don't check the return value of fork(), or their own process ID, and branch to different code paths based on it), then each subsequent fork will double the number of processes. So, yes, after three forks, you will end up with 2³ = 8 processes in total.
每个执行 a 的进程都会fork()变成两个进程(除非在异常错误情况下fork()可能会失败)。如果父子fork()进程继续执行相同的代码(即不检查 的返回值,或者自己的进程ID,并根据它分支到不同的代码路径),那么后续的每个fork 都会使进程数增加一倍。所以,是的,在三个 fork 之后,您最终将总共有 2³ = 8 个进程。

