Fork() linux issue



为什么程序打印 4 次"do"而不是只打印一次"do"?

法典:

#include<stdio.h>
#include<unistd.h>
int main()
{
printf(" do ");
if(fork()!=0) printf(" ma ");
if(fork()==0) printf(" to n ");
else printf("n");
}

程序打印做马做做马到do to

你在 "if" 语句中调用 fork 两次:

if(fork()!=0) printf(" ma ");
if(fork()==0) printf(" to n ");

在第一个分叉上,父 A 生成一个子 B,然后父级和子级都将第二次调用分叉。父项将生成子项 C,子项将生成子项 D。结果是 4 个过程:A、B、C、D。

A ---- B
|      |
C      D

由于您的打印被缓冲直到刷新到 stdout,并且每个分叉进程都会获得此缓冲区的副本,因此会打印四个"do"(检查@ilkkachu答案(。

如果你打算有一个"do",你应该这样做:

pid_t pid = fork();
if (pid > 0){
    printf(" do ");
    printf(" ma ");
} else {
    printf(" to n");
}

基本上将 fork(( 的返回存储在变量中,而不是在 "if" 语句中调用 fork 两次。

因为标准输出默认是行缓冲的(或者完全缓冲,如果将其重定向到文件或管道(。

第一个printf不命中换行符,因此它仅将字符串do添加到 C 库内部的缓冲区。在第一个fork,整个过程,包括那个缓冲区,是重复的。然后,其中一个副本将ma添加到其缓冲区,并且两个副本都是重复的(因为两个进程再次调用fork,而不仅仅是父进程或子进程。

最后,调用 printf(" to n ")printf("n"),生成换行符,触发缓冲区中任何内容的实际写入。

可以使用 fflush(stdout) 强制 C 库在分叉之前输出任何缓冲数据,也可以使用 setbuf(stdout, NULL) 完全禁用缓冲。