C语言管道中ls与more命令的子父进程职责为何不能调换?
管道父子进程职责调换后
more无法分页的问题分析 正常工作的代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main(int argc, char *argv[]) { int fd[2]; pid_t pid; if (pipe(fd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (pid == 0) { dup2(fd[1], STDOUT_FILENO); close(fd[0]); close(fd[1]); execlp("ls", "ls", NULL); perror("execlp"); exit(EXIT_FAILURE); } else { dup2(fd[0], STDIN_FILENO); close(fd[0]); close(fd[1]); execlp("more", "more", "-3", NULL); perror("execlp"); exit(EXIT_FAILURE); } }
这段代码中,子进程执行ls命令,父进程执行带-3参数的more命令,程序可正常分页显示(每次显示3行,按空格继续)。
无法正常工作的代码
if (pid != 0) { dup2(fd[1], STDOUT_FILENO); close(fd[0]); close(fd[1]); execlp("ls", "ls", NULL); perror("execlp"); exit(EXIT_FAILURE); } else { dup2(fd[0], STDIN_FILENO); close(fd[0]); close(fd[1]); execlp("more", "more", "-3", NULL); perror("execlp"); exit(EXIT_FAILURE); }
这段代码调换了子父进程的职责:父进程执行ls命令,子进程执行more命令,此时ls会输出全部目录内容,more无法正常分页工作。
问题原因解析
核心问题出在管道写端的生命周期和more的行为逻辑上:
more的分页逻辑:more只有在读取输入时遇到未读完的数据且当前输出已满一页时,才会暂停等待用户按键。如果它检测到输入已经到了EOF(管道写端关闭),就会直接输出剩余所有内容并退出,不会等待用户交互。父进程执行
ls的异常情况:- 父进程调用
execlp执行ls后,ls会尽可能向管道写入所有目录内容。如果管道被写满,ls会暂时阻塞,但只要more读取一部分数据,ls就会继续写入直到完成。 ls执行完毕后,父进程会直接退出,此时管道的写端被完全关闭(父进程是写端的持有者)。- 子进程的
more一旦检测到管道写端关闭(即输入到了EOF),就会放弃分页等待,直接把所有已读取和剩余的内容一次性输出,然后退出。
- 父进程调用
子进程执行
ls的正常情况:- 父进程的
more在输出满3行后会暂停,等待用户按键。此时管道的读端被挂起,管道内的数据会逐渐填满,导致子进程的ls因无法继续写入而阻塞。 - 直到用户按下空格,
more继续读取数据,管道空闲后ls才会继续写入。整个过程中,管道写端(子进程)始终处于打开状态,more不会收到EOF,因此会持续保持分页等待的逻辑。
- 父进程的
简单来说:父进程跑ls时,ls执行完毕后父进程直接退出,管道写端关闭,more知道没有后续数据,就一次性输出所有内容;子进程跑ls时,父进程的more持续运行,ls会被管道阻塞等待more读取数据,more始终能检测到后续还有数据,因此正常分页。
内容的提问来源于stack exchange,提问作者lostInTheWoodsZZ
相关产品推荐
相关产品推荐

