C语言使用fork+pipe实现ls|sort时pipefd[0]无输出无法打印问题
问题代码错误点
- 子进程错误调用
wait(NULL):wait系统调用的作用是等待当前进程的自身子进程退出,而执行sort的子进程本身没有创建任何子进程,该调用会直接报错返回,逻辑完全错误,也无法实现等待父进程写入数据的效果。 - 管道多余文件描述符未完全关闭:每个进程都持有管道读写端的独立副本,执行
ls的父进程仅需要管道写端,必须主动关闭不需要的读端;执行sort的子进程仅需要管道读端,必须主动关闭不需要的写端。如果管道的写端没有在所有进程中关闭,读端进程会一直阻塞等待数据,不会收到EOF,sort就不会输出结果。 - 资源清理代码位置错误:
execl调用成功后会完全替换当前进程的地址空间,后续的close代码永远不会执行,必须把管道描述符的关闭操作放在execl之前。
修正后完整代码
#include <unistd.h> #include <sys/wait.h> #include <sys/types.h> #include <stdio.h> int main(){ int pipefd[2]; if (pipe(pipefd) == -1) { perror("pipe error"); return 1; } int child = fork(); if (child == -1) { perror("fork error"); return 1; } if(!child){ // 子进程执行sort,读取管道内容 dup2(pipefd[0], 0); // 关闭子进程不需要的管道写端、已重定向的读端 close(pipefd[1]); close(pipefd[0]); execl("/bin/sort", "sort", NULL); perror("execl sort error"); return 1; }else{ // 父进程执行ls,写入管道 dup2(pipefd[1], 1); // 关闭父进程不需要的管道读端、已重定向的写端 close(pipefd[0]); close(pipefd[1]); execl("/bin/ls", "ls", NULL); perror("execl ls error"); return 1; } return 0; }
补充说明
父进程执行ls退出后,系统会自动关闭所有残留的文件描述符,此时管道写端完全关闭,sort读取到EOF后就会对所有输入排序并输出到标准输出。如果需要等待子进程执行完毕,可以在父进程逻辑中添加waitpid相关处理,不会影响管道数据的正常传递。
内容的提问来源于stack exchange,提问作者Juzar Antri
相关产品推荐
相关产品推荐

