问题描述
假设我们有一个全局变量 int a = 0
,a
会被打印多少次,第一个和最后一个值分别是多少?
for(int i=0; i<6; i++){
fork();
a++;
printf("a = %d\n",a)
}
printf("a = %d\n",a);
这是我所做的:
- i=0:又创建了一个线程,所以我现在有 2 个正在运行,它们都打印 (a=1,a=2),不知道哪个打印什么。
- i=1:这两个线程产生了更多的 2 个线程,所以我总共有 4 个线程,以及 4 个 (a=3,4,5,6)。
- i=3:现在有了 8,我们得到 (a=7,8,9,10,11,12,13,14)。
- 有 16 个,直到 a=30
- 32,直到 a=62。
到目前为止,我在循环的一侧有 2+4+8+16+32=62
,并且所有进程都到达外部循环额外 32,所以我总共得到 94
打印,第一个值是 a=1
和 a=62
最终值。
我很感激有关我的解决方案的任何反馈,因为我不确定如何在代码中测试它,因为我无法在 Windows 中使用 fork。
提前致谢!
解决方法
按如下所述修复并完成后,程序会在常见条件下打印 190 或 448 行,具体取决于其标准输出的定向。
首先,程序不会打印任何内容,因为 printf("a = %d\n",a)
后面没有分号,所以程序不会编译,因此不会执行。
假设我们添加了缺少的分号,包括 <stdio.h>
和 <unistd.h>
,将代码包装在 main
例程中,并在 Unix 环境中编译和执行。然后,在输出到交互式设备的情况下:
- 标准输出流是行缓冲的或无缓冲的。 (通常是前者,但它们将具有相同的效果,因为所有
printf
格式字符串都以\n
结尾。)每行将在发送到输出流后立即发送到设备。所以会在后面的fork
之前发送。 - 按照
i
的值对迭代进行编号,在迭代0中,一个进程变成了两个,a
从0到1(每个进程分别)递增,每个进程打印“a = 1”。所以打印了两行“a = 1”。 - 在迭代 1 中,两个进程变成了四个,
a
变成了 2,并且打印了四个“a = 2”。 - 在迭代 2 中,打印了八个“a = 3”。
- 在迭代 3 中,打印了 16 个“a = 4”。
- 在迭代 4 中,打印了 32 个“a = 5”。
- 在第 5 次迭代中,打印了 64 个“a = 6”。
- 循环后,在 64 个进程中的每一个进程中,
a
为 6,并且打印了 64 个“a = 6”。 - 因此我们有 2 + 4 + 8 + 16 + 32 + 64 + 64 = 190 行。
如果输出到磁盘上的文件或管道,则它是完全缓冲的。假设缓冲区足够大,可以容纳一个进程的所有输出。在这种情况下:
- 每一行都保存在缓冲区中,只有在程序退出时才会发送到设备。
- 在迭代 0 中,一个进程变为两个,
a
从 0 递增到 1,每个进程将“a = 1”打印到其缓冲区中。现在每个缓冲区都保存“a = 1”。 - 在迭代 1 中,两个进程变为四个,每个进程将“a = 2”打印到其缓冲区中。
- 在迭代 2 中,八个进程中的每一个都将“a = 3”打印到其缓冲区中。
- 在迭代 3 中,16 个进程中的每一个都将“a = 4”打印到其缓冲区中。
- 在第 4 次迭代中,32 个进程中的每一个都将“a = 5”打印到其缓冲区中。
- 在第 5 次迭代中,64 个进程中的每一个都将“a = 6”打印到其缓冲区中。
- 循环结束后,64 个进程中的每一个都将“a = 6”打印到其缓冲区中。
- 然后每个进程在准备退出时刷新其缓冲区。每个进程在其缓冲区中包含七行“a = 1”、“a = 2”、“a = 3”、“a = 4”、“a = 5”、“a = 6”和“a = 6” ”。因此,64 个进程中的每个进程打印 7 行,总共 448 行。
如果打印的行更长,或者每个进程有更多的行,它们有时可以填充缓冲区,并且进程会提前打印它们的行。这些行将不会被后面的分叉复制,并且打印的总数将介于最小值(从行缓冲输出)到最大值(从完全适合缓冲区的完全缓冲输出)之间。由于行尾与填充缓冲区不一致,我们还可能得到零碎的行。
,如果您无法运行 fork
,请模拟它。然后,您可以计算 fork
创建的进程数和 a
打印总数。
如果您想了解这种递归模型发生了什么,现在可以使用逐步调试。
#include <stdio.h>
int processes = 1;
int prints_of_a = 0;
void fake_fork(int a,int i) {
++ processes;
// behave like fork,start from inside loop
goto start_here;
for(; i<6; i++){
fake_fork(a,i);
start_here:
a++;
//printf("a = %d\n",a);
++ prints_of_a;
}
//printf("a = %d\n",a);
++ prints_of_a;
}
int main(int argc,char * argv[]) {
int a = 0;
for(int i=0; i<6; i++){
fake_fork(a,i);
a++;
//printf("a = %d\n",a);
++ prints_of_a;
printf("processes: %d\n",processes);
printf("prints a : %d\n",prints_of_a);
return 0;
}
输出:
processes: 64
prints a : 190