'a' 打印了多少次? 包括循环中的叉

问题描述

假设我们有一个全局变量 int a = 0a 会被打印多少次,第一个和最后一个值分别是多少?

for(int i=0; i<6; i++){
    fork();
    a++;
    printf("a = %d\n",a)
    }
printf("a = %d\n",a);

这是我所做的:

  1. i=0:又创建了一个线程,所以我现在有 2 个正在运行,它们都打印 (a=1,a=2),不知道哪个打印什么。
  2. i=1:这两个线程产生了更多的 2 个线程,所以我总共有 4 个线程,以及 4 个 (a=3,4,5,6)。
  3. i=3:现在有了 8,我们得到 (a=7,8,9,10,11,12,13,14)。
  4. 有 16 个,直到 a=30
  5. 32,直到 a=62。

到目前为止,我在循环的一侧有 2+4+8+16+32=62,并且所有进程都到达外部循环额外 32,所以我总共得到 94 打印,第一个值是 a=1a=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