fork进程代码重定向输出时重复打印内容的问题求解
解决父子进程中printf输出重定向重复的问题
问题场景
我编写了一段基于mmap实现父子进程共享内存的C代码:
#define _DEFAULT_SOURCE #include <stdio.h> #include <unistd.h> #include <sys/mman.h> #include <sys/wait.h> #include <stdlib.h> #include <sys/types.h> int main(){ int sum = 6; int *p = (int*) mmap(NULL, sizeof (int) , PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); *p = 7; printf("filled %d in memory\n", *p); int pID = fork(); if (pID == 0){ printf(" found %d\n", *p); printf(" sum inside %d\n",sum + (*p)); exit(0); } else if (pID> 0){ wait(NULL); printf("sum %d\n",sum+ *p); printf("exit\n"); exit(0); } return 0; }
直接在终端运行时输出正常:
filled 7 in memory found 7 sum inside 13 sum 13 exit
但执行./a.out > output.txt将输出重定向到文件时,filled 7 in memory会被重复打印,文件内容如下:
filled 7 in memory found 7 sum inside 13 filled 7 in memory //**printed twice sum 13 exit
问题原因
这是标准输出的缓冲机制差异导致的:
- 当标准输出指向终端时,默认是行缓冲模式,
printf中的换行符会触发缓冲区立即刷新,内容直接输出到终端。 - 当标准输出被重定向到文件时,默认是全缓冲模式,
printf的内容会先暂存在缓冲区中,还没来得及写入文件就执行了fork()。此时子进程会完整复制父进程的地址空间,包括未刷新的输出缓冲区。 - 后续父子进程退出时,都会各自刷新缓冲区,导致同一句内容被打印两次。
解决方法
方法1:fork前手动刷新缓冲区
在调用fork()之前,执行fflush(stdout)强制刷新标准输出缓冲区,确保内容已经写入文件,避免被子进程复制:
#define _DEFAULT_SOURCE #include <stdio.h> #include <unistd.h> #include <sys/mman.h> #include <sys/wait.h> #include <stdlib.h> #include <sys/types.h> int main(){ int sum = 6; int *p = (int*) mmap(NULL, sizeof (int) , PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); *p = 7; printf("filled %d in memory\n", *p); fflush(stdout); // 强制刷新缓冲区 int pID = fork(); if (pID == 0){ printf(" found %d\n", *p); printf(" sum inside %d\n",sum + (*p)); exit(0); } else if (pID> 0){ wait(NULL); printf("sum %d\n",sum+ *p); printf("exit\n"); exit(0); } return 0; }
方法2:禁用标准输出缓冲
在程序开头调用setvbuf(stdout, NULL, _IONBF, 0),将标准输出设置为无缓冲模式,这样每次printf都会直接输出内容,不会暂存到缓冲区:
#define _DEFAULT_SOURCE #include <stdio.h> #include <unistd.h> #include <sys/mman.h> #include <sys/wait.h> #include <stdlib.h> #include <sys/types.h> int main(){ setvbuf(stdout, NULL, _IONBF, 0); // 设置无缓冲 int sum = 6; int *p = (int*) mmap(NULL, sizeof (int) , PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); *p = 7; printf("filled %d in memory\n", *p); int pID = fork(); if (pID == 0){ printf(" found %d\n", *p); printf(" sum inside %d\n",sum + (*p)); exit(0); } else if (pID> 0){ wait(NULL); printf("sum %d\n",sum+ *p); printf("exit\n"); exit(0); } return 0; }
内容的提问来源于stack exchange,提问作者fatihbulbul1
相关产品推荐
相关产品推荐

