execlp调用异常:父子进程管道通信程序运行冻结排查
解决管道+more命令导致程序冻结的问题
嘿,我之前也碰到过一模一样的管道阻塞问题!看你贴的代码开头,结合你说的程序冻结情况,大概率是管道的文件描述符没有正确关闭,或者子进程的标准输入重定向没做对——毕竟more命令会一直等待输入,直到收到EOF才会退出,要是管道的写端没关,它就会一直卡着等数据。
常见的几个坑(也是我当初踩过的):
- 父进程写完数据后没有关闭管道的写端:
more会一直监听stdin,只要写端还被持有,就认为还有数据要传,不会退出。 - 子进程没有把管道读端重定向到标准输入:
more默认从stdin读,你得手动把管道的读端替换成stdin。 - 父进程没有等待子进程执行完毕:可能导致子进程变成僵尸,或者管道状态异常。
修正后的完整代码示例
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <string.h> int main(void) { int fd[2]; pid_t pid; // 创建管道 if (pipe(fd) == -1) { perror("Error creating pipe"); exit(EXIT_FAILURE); } // 创建子进程 pid = fork(); if (pid == -1) { perror("Error forking process"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程逻辑:调用more命令 // 1. 关闭不需要的写端(子进程只需要读数据) close(fd[1]); // 2. 将管道读端重定向到标准输入(stdin) if (dup2(fd[0], STDIN_FILENO) == -1) { perror("Error redirecting stdin"); exit(EXIT_FAILURE); } // 3. 关闭原来的管道读端(已经通过dup2复制到stdin了) close(fd[0]); // 4. 调用more命令,这里用execlp更方便 execlp("more", "more", NULL); // 如果execlp返回,说明调用失败 perror("Error executing more"); exit(EXIT_FAILURE); } else { // 父进程逻辑:写100行数据到管道 // 1. 关闭不需要的读端(父进程只需要写数据) close(fd[0]); // 2. 写入100行内容 char buf[100]; for (int i = 0; i < 100; i++) { snprintf(buf, sizeof(buf), "这是第%d行测试内容\n", i+1); write(fd[1], buf, strlen(buf)); } // 3. 关键!写完后必须关闭写端,这样more才会收到EOF并退出 close(fd[1]); // 4. 等待子进程执行完毕,避免僵尸进程 waitpid(pid, NULL, 0); } return EXIT_SUCCESS; }
关键步骤解释
- 管道两端的关闭策略:
- 父进程只需要写,所以fork后立刻关闭读端
fd[0];写完数据后必须关闭写端fd[1],这是让more退出的核心——否则more会一直等新数据,程序就冻结了。 - 子进程只需要读,所以fork后立刻关闭写端
fd[1];重定向stdin后关闭原来的读端fd[0],避免文件描述符泄漏。
- 父进程只需要写,所以fork后立刻关闭读端
- 标准输入重定向:用
dup2(fd[0], STDIN_FILENO)把管道的读端绑定到stdin,这样more就会从管道读取数据,而不是终端输入。 - 等待子进程:父进程用
waitpid等待子进程结束,确保程序流程正常,不会出现父进程先退出导致的异常。
你可以对照你的代码,看看是不是漏掉了这些关键步骤——尤其是写完数据后关闭写端这一步,我当初就是因为忘了这个,卡了快半小时!
内容的提问来源于stack exchange,提问作者Pedro
相关产品推荐
相关产品推荐

