[英]Visually what happens to fork() in a For Loop
I have been trying to understand fork()
behavior. 我一直在试图理解
fork()
行为。 This time in a for-loop
. 这次是
for-loop
。 Observe the following code: 请注意以下代码:
#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 hi statements.
我的导师说会有8个hi语句。 I wrote and ran the code, and indeed there were 8 hi statements.
我编写并运行了代码,确实有8个hi语句。 But I really didn't understand it.
但我真的不明白。 So I drew the following diagram:
所以我画了下面的图:
Diagram updated to reflect comments :) 图更新以反映评论:)
i=0
in the output? i=0
实例? i
is carried over to each child after the fork()? i
每个孩子的价值是多少? If the same value of i
is carried over, then when does the "forking" stop? i
值相同,那么“分叉”何时停止? 2^n - 1
would be a way to count the number of children that are forked? 2^n - 1
将是一种计算分叉儿童数量的方法吗? So, here n=3
, which means 2^3 - 1 = 8 - 1 = 7
children, which is correct? n=3
,这意味着2^3 - 1 = 8 - 1 = 7
孩子,这是正确的吗? Here's how to understand it, starting at the for
loop. 从
for
循环开始,这是如何理解它的。
Loop starts in parent, i == 0
循环从父开始,
i == 0
Parent fork()
s, creating child 1. 父
fork()
,创建子1。
You now have two processes. 您现在有两个进程。 Both print
i=0
. 两者都打印
i=0
。
Loop restarts in both processes, now i == 1
. 循环在两个进程中重新启动,现在
i == 1
。
Parent and child 1 fork()
, creating children 2 and 3. 父和子1
fork()
,创建子级2和3。
You now have four processes. 您现在有四个流程。 All four print
i=1
. 全部四个打印
i=1
。
Loop restarts in all four processes, now i == 2
. 循环在所有四个进程中重新启动,现在
i == 2
。
Parent and children 1 through 3 all fork()
, creating children 4 through 7. 父母和孩子1到3都是
fork()
,创建4到7岁的孩子。
You now have eight processes. 你现在有八个进程。 All eight print
i=2
. 所有八个打印
i=2
。
Loop restarts in all eight processes, now i == 3
. 循环在所有八个进程中重新启动,现在
i == 3
。
Loop terminates in all eight processes, as i < 3
is no longer true. 循环在所有八个进程中终止,因为
i < 3
不再为真。
All eight processes print hi
. 所有八个过程打印
hi
。
All eight processes terminate. 所有八个进程终止。
So you get 0
printed two times, 1
printed four times, 2
printed 8 times, and hi
printed 8 times. 所以,你得到
0
印刷两次, 1
印刷四次, 2
印刷8次, hi
印刷8次。
i++
is executed after the call of fork
, because that's the way the for
loop works. fork
之后执行i++
,因为这就是for
循环的工作方式。 fork
may fail. 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 i
in the forked processes(both parent and child) is the value before increment. 所以
i
在分叉进程(父对象和子进程)中都是增量前的值。 However, the increment is executed immediately after fork()
, so in my opinion, the diagram could be treat as correct. 但是,在
fork()
之后立即执行增量,所以在我看来,图表可以被视为正确。
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=0
etc. labels as referring to full loop iterations. 也就是说,如果将
i=0
等标签解释为指向完整循环迭代,则是正确的。 What the diagram doesn't show, 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. 然而,该图未显示的是,在每个
fork()
之后, fork()
调用之后的当前循环迭代的部分也由分叉的子进程执行。
Why are there two instances of
i=0
in 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. 因为
fork()
printf()
之后有printf()
,所以它由父进程和刚分叉的子进程执行。 If you move the printf()
before the fork()
, it will only be executed by the parent (since the child process doesn't exist yet). 如果在
fork()
printf()
之前移动printf()
,它将仅由父项执行(因为子进程尚不存在)。
What value of
i
is carried over to each child after thefork()
?在
fork()
之后,i
每个孩子的价值是多少? If the same value ofi
is carried over, then when does the "forking" stop?如果
i
值相同,那么“分叉”何时停止?
The value of i
is not changed by fork()
, so the child process sees the same value as its parent. fork()
不会更改i
的值,因此子进程看到的值与其父进程相同。
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). fork()
创建的子进程是其父级的(几乎)精确克隆,因此,从它自己的角度来看,它“记住”作为其父级,继承所有父进程的状态(包括所有变量值,调用)堆栈和正在执行的指令)。 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. 唯一的直接差异(除了系统元数据,例如
getpid()
返回的进程ID)是fork()
的返回值,它在子进程中为零但非零(实际上是子进程的ID) )在父母。
Is it always the case that
2^n - 1
would be a way to count the number of children that are forked?总是这样的情况,
2^n - 1
将是一种计算分叉儿童数量的方法吗? So, heren=3
, which means2^3 - 1 = 8 - 1 = 7
children, which is correct?那么,这里
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). 执行
fork()
每个进程都会变成两个进程(除非在异常错误条件下, fork()
可能会失败)。 If the parent and child keep executing the same code (ie 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. 如果父和子继续执行相同的代码(即他们不检查
fork()
的返回值,或者他们自己的进程ID,并根据它分支到不同的代码路径),那么每个后续的fork将使数字加倍进程 So, yes, after three forks, you will end up with 2³ = 8 processes in total. 所以,是的,在三把叉之后,你最终会得到2³= 8个进程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.