父进程kill子进程后read()与printf()无响应问题排查
问题排查与修复方案
先给你捋清楚代码里的核心问题,以及对应的修复方法:
现象根源分析
- 父进程printf内容不显示:你写的
printf("NOTHING IS PRINTING HERE ")换行写法错误(应为\n);且stdout默认是行缓冲,即便换行正确,父进程发送信号后直接结束,缓冲内容可能还没来得及刷到终端,导致输出丢失。 - read无响应/父进程直接退出:发送
SIGTERM后,子进程需要时间处理信号、输出内容,但父进程未等待子进程完成操作就直接结束,管道读端被提前关闭,子进程的输出无法写入管道,父进程自然读不到内容。 - 子进程输出丢失风险:程序
a的SIGTERM处理函数如果没显式调用fflush(stdout),输出内容会滞留在用户态缓冲中,子进程被终止时缓冲内容直接丢失,无法写入管道。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <signal.h> int main() { int pid, childpid; int fd1[2], fd2[2]; int input = 10; // 增加管道创建错误检查 if (pipe(fd1) == -1 || pipe(fd2) == -1) { perror("pipe 创建失败"); exit(EXIT_FAILURE); } for (int signal = 0; signal < 2; signal++) { input += 2; char str[20]; if (signal == 0) { pid = fork(); if (pid == -1) { perror("fork 失败"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程逻辑 childpid = getpid(); // 重定向标准输入输出到管道 dup2(fd1[0], STDIN_FILENO); dup2(fd2[1], STDOUT_FILENO); // 关闭所有未使用的管道描述符,避免资源泄漏 close(fd1[0]); close(fd1[1]); close(fd2[0]); close(fd2[1]); // 执行程序a,失败输出错误信息 if (execlp("./a", "./a", NULL) < 0) { perror("execlp 执行失败"); exit(EXIT_FAILURE); } } else { // 父进程逻辑:关闭不用的管道端 close(fd1[0]); close(fd2[1]); // 向子进程写入输入 write(fd1[1], &input, sizeof(input)); sleep(2); // 读取子进程输出 int nbytes = read(fd2[0], str, sizeof(str)); printf("第一次读取子进程字节数: %d\n", nbytes); fflush(stdout); // 强制刷新缓冲,确保内容实时显示 } } if (signal == 1) { // 向子进程写入输入 write(fd1[1], &input, sizeof(input)); // 发送终止信号 kill(childpid, SIGTERM); // 修正换行符,加fflush确保输出立即显示 printf("NOTHING IS PRINTING HERE\n"); fflush(stdout); // 读取子进程终止前的输出内容 int nbytes = read(fd2[0], str, sizeof(str)); if (nbytes > 0) { printf("子进程终止时输出: %.*s\n", nbytes, str); } // 等待子进程完全退出,确保信号处理和输出操作完成 waitpid(childpid, NULL, 0); } } // 父进程关闭剩余管道描述符 close(fd1[1]); close(fd2[0]); return 0; }
程序a的必要修改
程序a的SIGTERM信号处理函数必须显式刷新stdout,否则输出内容会丢失,示例代码:
#include <stdio.h> #include <signal.h> #include <stdlib.h> void handle_sigterm(int sig) { printf("收到SIGTERM,准备终止\n"); fflush(stdout); // 强制将缓冲内容写入管道 exit(EXIT_SUCCESS); } int main() { // 注册SIGTERM信号处理函数 signal(SIGTERM, handle_sigterm); // 读取父进程发来的输入 int input; read(STDIN_FILENO, &input, sizeof(input)); printf("收到输入: %d\n", input); fflush(stdout); // 保持运行,等待信号触发 while(1); return 0; }
关键修复点总结
- 修正printf换行符为标准
\n,并添加fflush(stdout)强制刷新缓冲,解决父进程输出不显示的问题; - 使用
waitpid等待子进程退出,给子进程足够时间完成信号处理和输出操作; - 在
signal==1分支中添加子进程输出读取逻辑,获取终止前的内容; - 程序
a的信号处理函数必须调用fflush(stdout),避免缓冲内容丢失; - 完善管道、fork的错误检查,便于问题排查;
- 关闭所有未使用的管道描述符,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Addscott
相关产品推荐
相关产品推荐

