'a' 打印了多少次? (包括循环中的 fork)

How many times 'a' is printed? (includes fork in a loop)

假设我们有一个全局变量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=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(每个进程分别),每个进程打印“一个 = 1”。所以打印了两行“a = 1”。
  • 第1次迭代,2个进程变成4个,a变成2个,打印出4个“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("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