Fork系统调用中文件描述符与I/O缓冲区的处理问题
关于fork复制文件描述符与I/O缓冲区的问题解答
核心原因在于C标准库的缓冲策略差异,fork本身不会主动刷新任何缓冲区,两个案例的区别完全由输出目标的缓冲模式决定:
案例1:输出到stdout(终端)时的情况
当stdout指向终端设备时,默认采用行缓冲模式。你代码中的printf("start")即便没有换行符,实际运行时也可能因终端交互特性、后续进程退出时的自动刷新,导致缓冲区内容被一次性输出;fork时子进程复制的是空缓冲区,因此"start"只打印一次。
你之前认为“fork在复制缓冲区前刷新了I/O缓冲区”是误解——fork本身不会执行刷新操作,问题根源是终端输出的行缓冲特性。
案例2:输出到文件时的情况
当输出目标是普通文件时,C标准库默认采用全缓冲模式。fprintf(fd, "Started\n")执行后,数据只会留在用户空间的缓冲区中,不会立即写入磁盘。此时调用fork,子进程会完整复制父进程的整个地址空间,包括这个未刷新的缓冲区。后续:
- 子进程调用
fclose(fd)时,会自动刷新缓冲区,将"Started\n"写入文件 - 父进程在wait后调用
fclose(fd),同样会刷新自己的缓冲区,再次写入"Started\n"
最终文件中就会出现两次"Started\n"。
针对测试代码的解决方案
要避免重复写入,只需在fork前主动刷新缓冲区即可:
fprintf(fd, "Started\n"); fflush(fd); // 主动刷新缓冲区,将数据写入磁盘 pid = fork();
这样fork时缓冲区已经是空的,父子进程后续的写入就不会重复输出"Started\n"。
另外,也可以在fork后只让一个进程负责关闭文件并刷新缓冲区,或者打开文件时指定无缓冲模式(fopen("filename.txt", "wb", _IONBF)),不过主动刷新是最直观的解决方案。
内容的提问来源于stack exchange,提问作者Yashaswi
相关产品推荐
相关产品推荐

