有人可以解释一下这个程序创建了多少个子进程吗? 答案是127,但我不明白他们是怎么得到的。
int create(int num){
int i;
for(i=0;i<num;i++)
fork();
}
int main() {
int i;
fork();
for(i=0;i<4;i++)
create(i);
return 0;
}
这听起来确实像是操作系统课程的作业问题,但这是一个有趣的问题,所以我会为您解答。首先,我们看一下代码,如下所示。从功能上来说,它是一样的,但它会让事情更容易理解。另外,首先,让我们忽略最初的
fork()
调用。如果不存在,我们将计算有多少个,然后如果我们将其添加回来,我们将拥有相同数量的进程,乘以两倍。
int main() {
int i, j;
// fork();
for (i = 0; i < 4; i++) {
for (j = 0; j < i; j++) {
fork();
}
}
}
现在这部分是一个数学问题,部分是一个编程问题。首先,我们需要了解当我们调用
fork()
时会发生什么。当您创建子进程时,子进程会继承其自己的所有父进程变量的副本,这些变量的当前值是进行 fork()
调用时的变量的当前值。因此,这意味着现在,父级和子级拥有具有完全相同值的完全相同变量的副本,但它们可以独立修改这些变量,并且不会相互影响。那么在下面的简单例子中,
int main() {
int i = 0, pid = fork();
if (pid == 0) {
i = 1;
}
if (pid > 0) {
i = 2;
}
}
在父母的世界中,
i
获取值2,在孩子的世界中i
获取值1,这些现在是我们正在讨论的单独变量,因此父母可以拥有它想要的东西,孩子也可以各有所求,不冲突,皆大欢喜。
现在,为了回答您的问题,我们必须牢记这一点。因此,让我们看看在没有最初的
fork()
调用的情况下,我们首先有多少个进程。现在,父进程本身将生成 6 个子进程。对于每个过程,变量 (i,j)
将具有值 (1,0)、(2,0)、(2,1)、(3,0)、(3,1) 和 (3,2) ,分别。
因此在 (3,2) 处生成的最后一个子级将退出循环,并且不会生成更多子级。在 (3,1) 处生成的子进程将继续 for 循环,递增
j
,生成另一个进程,然后两个子进程都会在 (3,2) 处看到 (i,j)
,退出 for 循环,然后死亡。然后我们在 (3,0) 处由父级生成了另一个子级。现在,这个孩子将继续执行 for 循环,在 (3,1) 和 (3,2) 处生成一个孩子,然后死亡,然后在 (3,1) 处生成的这个新孩子将生成另一个孩子,然后它们会死的。我认为我们可以看到这开始变得相当复杂,所以我们可以用下图来表示这种情况。
图中的每个顶点代表一个进程,标记为 p 的顶点是父进程。每条边上的有序对表示子进程生成时的
(i,j)
值。请注意我们如何对流程进行分组。在第一组中,我们有 1 个进程,接下来有 2 个进程,接下来是 4 个进程,然后是 8 个进程,现在我们应该看看事情进展如何。下一组将有 16 个进程,下一组将有 32 个进程。因此,如果我们计算所有进程(包括父进程),我们将有 64 个进程。到目前为止有意义吗?
现在让我们把最初的
fork()
回调放回去。这将导致我们刚才描述的完全相同的情况发生两次,这将给我们总共 128 个进程,包括父进程,这意味着我们已经生成了 127 个子进程.
是的,一半是数学问题,一半是编程问题。让我知道你的问题。
您可以将第一个循环重写为
for (i = 1; i <= n; i++)
。那么我很确定我们可以说,一般来说,您的父进程将产生 子进程,其中
如果你写
for (int i = 0; i < 4; i++) {
for (int j = 0; j < i; j++) {
fork();
}
}
相当于
fork();
fork();
.
.
.
fork();
其中 N 是分叉总数,进程总数将为 2^N。由于一个进程是父进程,因此减去一,就剩下子进程的数量。
当你对大脑中的 3 个叉子进行小型模拟时,很容易找到这种逻辑
fork();
fork();
fork();
第一个 fork 克隆了父进程,我们最终得到了两个相同的进程,它们都将继续执行程序中的下一个 fork。你可以把它想象成分裂,我喜欢这样想,一个进程在每个叉子上分裂成两个。
然后是时候让他们俩执行程序中的第二个fork了。他们再次“分裂”,最终总共有 4 个进程。
那么第三个fork必须由所有4个进程执行,这将导致进一步分裂,导致总共8个进程,其中一个是父进程。
现在我们知道每个连续的分叉都会使进程数量加倍,您所要做的就是计算整个程序中发生的分叉数量。 (假设代码中没有条件分支,父进程和子进程必须执行代码的相同部分)