C语言实现管道调用grep时子进程阻塞无法退出求助
问题分析与解决
你的grep子进程卡住无法退出的核心原因是父进程没有关闭管道的读写两端。当ls子进程执行完毕退出后,管道的写端仍被父进程保持打开状态,grep会一直等待管道中出现新数据,无法触发EOF(文件结束符),因此会持续阻塞无法正常退出。
具体修复步骤
- 父进程关闭管道两端:在fork完成所有子进程后,父进程必须主动关闭
pfd[0]和pfd[1],让管道的写端完全关闭,grep读取到EOF后就会正常结束。 - 子进程关闭冗余描述符:虽然
execvp会替换进程地址空间,但在dup2后关闭原管道描述符是更规范的做法,避免不必要的资源泄漏。
修复后的代码示例
#include <sys/wait.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> int main() { int i = 0; int pfd[2]; if (pipe(pfd) != 0) { printf("Error creating pipe\n"); exit(errno); } char **ptr = get_pipes(); // pipes as array of strings char *command = *ptr; while (command != NULL) { if (i == 2) break; // hard code to ignore all commands after 2nd pipe char **args = parse_cmd(command); // this parses a space-separated command as arguments pid_t pid = fork(); if (pid == 0 && i == 0) // 1st pipe, 1st child { close(pfd[0]); // 关闭管道读端 dup2(pfd[1], 1); // 将标准输出重定向到管道写端 close(pfd[1]); // 关闭原管道写端,避免资源泄漏 if (execvp(args[0], args) == -1) { fprintf(stderr, "%s: %s\n", args[0], strerror(errno)); exit(EXIT_FAILURE); } } else if (pid == 0 && i == 1) // 2nd pipe, 2nd child { close(pfd[1]); // 关闭管道写端 dup2(pfd[0], 0); // 将标准输入重定向到管道读端 close(pfd[0]); // 关闭原管道读端,避免资源泄漏 if (execvp(args[0], args) == -1) { fprintf(stderr, "'%s': %s\n", args[0], strerror(errno)); exit(EXIT_FAILURE); } } else if (pid > 0) // parent { printf("Parent pid: %d and child's pid is %d\n", (int)getpid(), (int)pid); } command = *++ptr; i++; } // 父进程必须关闭管道两端,否则grep会一直阻塞等待 close(pfd[0]); close(pfd[1]); pid_t zombie_pid; int status; do { zombie_pid = waitpid(-1, &status, 0); if (zombie_pid > 0) { printf("Child PID %d died with status %d\n", (int)zombie_pid, WEXITSTATUS(status)); } } while (zombie_pid > 0); }
额外说明
- 管道的读写端必须被所有不再使用它的进程关闭,否则依赖EOF判断结束的进程(如
grep、cat等)会持续阻塞。 - 修复后的
waitpid循环增加了判断,避免所有子进程退出后,zombie_pid为-1时输出错误信息。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

