进程通信代码疑问:先回收子进程会导致无法打印吗?如何解决?
问题分析与解决方案
结论
确实存在无法正常打印的情况。
问题原因
当前代码存在两个核心问题:
- 父进程持有管道写端未关闭:父进程创建管道后,没有关闭管道的读写描述符。当第二个子进程写入数据退出后,父进程仍持有管道写端,导致第一个子进程的
read()调用会一直阻塞(因为管道写端并未完全关闭,不会触发EOF),程序卡住无法打印内容。 - 子进程输出缓冲未刷新:第二个子进程中
printf("HI")没有换行符,stdout默认是行缓冲模式,数据可能被暂时缓存,无法立即写入管道,进一步加剧阻塞问题。
解决方法
通过三个关键点修复代码:
修复后的代码示例
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <sys/wait.h> int main() { pid_t c[2]; int p[2]; // 增加管道创建错误检查 if (pipe(p) == -1) { fprintf(stderr, "pipe error"); exit(EXIT_FAILURE); } c[0] = fork(); if (c[0] < 0) { fprintf(stderr, "fork error"); exit(EXIT_FAILURE); } else if (c[0] == 0) { // 第一个子进程:读取管道数据 close(p[1]); // 关闭未使用的写端 dup2(p[0], STDIN_FILENO); // 安全替换标准输入 close(p[0]); // 复制后关闭原描述符 char buf[BUFSIZ]; ssize_t n = read(STDIN_FILENO, buf, BUFSIZ); if (n > 0) { buf[n] = '\0'; // 手动添加字符串终止符,避免垃圾字符 printf("Second child's print: %s\n", buf); } exit(EXIT_SUCCESS); } c[1] = fork(); if (c[1] < 0) { fprintf(stderr, "fork error"); exit(EXIT_FAILURE); } else if (c[1] == 0) { // 第二个子进程:写入管道数据 close(p[0]); // 关闭未使用的读端 dup2(p[1], STDOUT_FILENO); // 安全替换标准输出 close(p[1]); // 复制后关闭原描述符 printf("HI"); fflush(stdout); // 强制刷新缓冲区,确保数据立即写入管道 exit(EXIT_SUCCESS); } // 父进程关闭管道所有描述符,避免持有写端导致子进程阻塞 close(p[0]); close(p[1]); // 等待两个子进程结束,顺序不影响 if (waitpid(c[0], NULL, 0) == -1 || waitpid(c[1], NULL, 0) == -1) { exit(EXIT_FAILURE); } return 0; }
关键修复点说明
- 父进程关闭管道描述符:父进程不使用管道,创建完子进程后立即关闭管道的读写描述符,确保第二个子进程退出后,管道写端完全关闭,第一个子进程的
read()能正常读取数据并结束。 - 用
dup2()替代手动操作:dup2()可以安全替换文件描述符,避免手动关闭标准输入/输出后出错的情况。 - 强制刷新输出缓冲区:调用
fflush(stdout)确保"HI"不被缓冲,立即写入管道,让第一个子进程能及时读取到数据。 - 检查
read()返回值:避免读取失败或EOF时打印垃圾字符,手动添加字符串终止符保证输出格式正确。
内容的提问来源于stack exchange,提问作者iyeaaa
相关产品推荐
相关产品推荐

