使用cat做管道缓冲的C程序写入后挂起,如何检查cat进程状态?
解决向管道写入后挂起并检查cat进程是否完成的问题
我来帮你搞定这个问题!你遇到的挂起其实是管道的典型死锁场景,咱们一步步拆解解决:
核心问题分析
你的程序挂起的根源是管道读写端没有正确关闭:当你创建管道并fork出cat进程后,主进程仍然持有管道的写端,cat进程会一直监听管道输入,直到所有写端都被关闭才会结束;而主进程如果在等待cat退出,就会形成互相等待的死锁。
修正后的示例代码
下面是修复后的完整代码,我会在后面标注关键改动点:
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <sys/wait.h> #include <string.h> #include <unistd.h> #define PIPE_READ 0 #define PIPE_WRITE 1 int main(int argc, char** argv) { int pipe_fd[2]; pid_t cat_pid; // 创建管道 if (pipe(pipe_fd) == -1) { perror("pipe failed"); exit(EXIT_FAILURE); } // fork出cat进程 cat_pid = fork(); if (cat_pid == -1) { perror("fork failed"); exit(EXIT_FAILURE); } if (cat_pid == 0) { // 子进程:执行cat,从管道读数据 close(pipe_fd[PIPE_WRITE]); // 关闭子进程不需要的写端 dup2(pipe_fd[PIPE_READ], STDIN_FILENO); // 把管道读端重定向到标准输入 close(pipe_fd[PIPE_READ]); // 重定向后关闭原文件描述符 execlp("cat", "cat", NULL); // 执行cat命令 perror("execlp failed"); // 如果execlp返回,说明出错 exit(EXIT_FAILURE); } else { // 父进程:向管道写数据 close(pipe_fd[PIPE_READ]); // 关闭父进程不需要的读端 // 写入测试数据 const char* data = "Hello from parent process!\nAnother line.\n"; if (write(pipe_fd[PIPE_WRITE], data, strlen(data)) == -1) { perror("write failed"); exit(EXIT_FAILURE); } close(pipe_fd[PIPE_WRITE]); // 关键:写完后立即关闭写端,让cat知道没有更多输入 // 检查cat进程是否完成 int status; pid_t wait_result = waitpid(cat_pid, &status, 0); if (wait_result == -1) { perror("waitpid failed"); exit(EXIT_FAILURE); } // 判断进程退出状态 if (WIFEXITED(status)) { printf("cat进程正常退出,退出码:%d\n", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("cat进程被信号终止,信号编号:%d\n", WTERMSIG(status)); } } return EXIT_SUCCESS; }
关键操作说明
- 关闭无关管道端:不管父进程还是子进程,都要关闭自己不需要的管道端。子进程只需要读,所以关闭写端;父进程只需要写,所以关闭读端——这是管道使用的基本规范,避免进程误以为还有数据会进来。
- 写完后立即关闭写端:这是解决挂起的核心!当父进程写完数据后,必须关闭管道的写端,这样cat进程读到管道的EOF后就会自动退出,不会一直阻塞等待输入。
- 用waitpid检查进程状态:通过
waitpid(cat_pid, &status, 0)可以阻塞等待cat进程结束,并获取它的退出状态:WIFEXITED(status):判断进程是否正常退出WEXITSTATUS(status):获取正常退出的退出码WIFSIGNALED(status):判断进程是否被信号杀死WTERMSIG(status):获取终止进程的信号编号
非阻塞检查进程状态的方案
如果你不想让主进程阻塞等待cat,可以用非阻塞模式定期检查:
// 非阻塞检查示例 bool cat_finished = false; while (!cat_finished) { int status; pid_t result = waitpid(cat_pid, &status, WNOHANG); if (result == cat_pid) { // cat进程已结束 cat_finished = true; if (WIFEXITED(status)) { printf("cat正常退出,退出码:%d\n", WEXITSTATUS(status)); } else { printf("cat被信号终止,信号:%d\n", WTERMSIG(status)); } } else if (result == 0) { // cat还在运行,父进程可以做其他操作 printf("cat进程仍在运行...\n"); sleep(1); } else { // 出错 perror("waitpid failed"); break; } }
内容的提问来源于stack exchange,提问作者Simon Baars
相关产品推荐
相关产品推荐

