调用fork()后输出的额外数据

Dea*_*orf 2 c fork multiprocessing

我正在运行以下代码,我在Mac上用c编写.

#include <unistd.h>
#include <stdio.h>  

int main(int argc, const char * argv[]) {

    int i = 0;
    printf("Starting pid:%d\n", getpid());
    while(i++<3){
        int ret = fork();
        printf("hello(%d)%d, %d ", i, getpid(), ret);
        if(!ret){
            printf("\n");
            return 0;}
    }
}
Run Code Online (Sandbox Code Playgroud)

我想到的目标是共有6张照片 - 其中3张来自原始父母(pid印在"Starting pid"中),还有1张来自3个衍生儿童.相反,我收到的是:

Starting pid:7998
hello(1)8009, 0 
hello(1)7998, 8009 hello(2)8010, 0 
hello(1)7998, 8009 hello(2)7998, 8010 hello(3)7998, 8011 hello(1)7998, 8009 hello(2)7998, 8010 hello(3)8011, 0 
Run Code Online (Sandbox Code Playgroud)

请注意,原始父级(7998)打印6次(当i == 1时为三次,i == 2时为两次,i == 3时为一次).

为什么会这样?为什么我没有从父母那里收到3份照片(一次当i == 1,i == 2,i == 3).如果我们从父母的角度来看它 - 有一个while循环,我们应该只打3次内部的print语句.

是叉子是异步还是什么?我错过了什么?

dbu*_*ush 7

fork进程中,父进程中的内存在子进程中重复.这包括stdout缓冲区.

从父级循环的第二次迭代开始,您已hello(1)7998, 8009进入缓冲区.当第二个孩子分叉时,这个文本仍然在那个孩子的缓冲区中.然后第二个孩子打印hello(2)8010, 0,然后换行.换行刷新孩子的缓冲区,所以第二个孩子打印出来:

hello(1)7998, 8009 hello(2)8010, 0 
Run Code Online (Sandbox Code Playgroud)

在fork之后,父打印hello(2)7998, 8010将添加到输出缓冲区.然后在第三次迭代中,第三个子进程继承并打印:

hello(1)7998, 8009 hello(2)7998, 8010 hello(3)8011, 0
Run Code Online (Sandbox Code Playgroud)

然后父母打印hello(3)7998, 8011出再次添加到缓冲区的内容.然后父节点退出循环并退出,之后刷新缓冲区并输出父节点:

hello(1)7998, 8009 hello(2)7998, 8010 hello(3)7998, 8011
Run Code Online (Sandbox Code Playgroud)

要纠正此问题,父进程需要在分叉之前清除输出缓冲区.

这可以通过调用fflush(stdout)后调用printf,或者通过添加换行符(\n)来完成printf.

编辑:

作为更通用的解决方案,调用fflush(NULL)将刷新所有打开的输出流.