You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

minishell管道实现中关闭写端未向另一进程发送EOF的问题

问题原因

你遇到的问题核心是子进程没有关闭自身不使用的管道文件描述符,导致管道写端的引用计数无法归零,读端进程永远收不到EOF。

具体逻辑拆解

  • 调用pipe(pipefd)创建管道后,父进程持有pipefd[0](读端)和pipefd[1](写端)两个文件描述符,每次fork子进程时,子进程会完整继承这两个fd,此时两个管道fd的内核引用计数都会随着fork递增。
  • 管道读端收到EOF的前提是:所有持有管道写端的进程都主动关闭了该写端。
  • 你的代码中,左边写管道的子进程(执行ls的i=0进程)、右边读管道的子进程(执行wc的i=1进程)都继承了管道的写端pipefd[1],且都没有主动关闭:
    即使后续父进程关闭了自己持有的pipefd[1],读端子进程仍然持有pipefd[1]的引用,管道写端总引用计数不会降到0,内核不会给读端发送EOF,wc就会一直阻塞在读标准输入的操作中。
  • 如果替换为不需要读管道的命令(比如printenv),命令不会等待管道输入,所以能正常执行,符合你观察到的现象。

修复方案

在子进程ft_exec函数中,执行dup2前后关闭不需要的管道fd即可:

void    ft_exec(int i)
{
    char **ls = malloc(sizeof(char *) * 2);
    ls[0] = "/bin/ls";
    ls[1] = NULL;

    char **wc = malloc(sizeof(char *) * 3);
    wc[0] = "/usr/bin/wc";
    wc[1] = "-l";
    wc[2] = NULL;

    printf("ENTERED BY %d\n", getpid());
    if (i == 0)
    {
        // 写进程不需要管道读端,先关闭
        close(pipefd[0]);
        dup2(pipefd[1], 1);
        // dup2完成后,原管道写端已经不需要,可以关闭
        close(pipefd[1]);
        execve(ls[0], ls, environ);
    }
    if (i == 1)
    {
        // 读进程不需要管道写端,先关闭
        close(pipefd[1]);
        dup2(pipefd[0], 0);
        // dup2完成后,原管道读端已经不需要,可以关闭
        close(pipefd[0]);
        execve(wc[0], wc, environ);
    }
}

额外优化:父进程可以在fork完所有子进程后,直接关闭自己持有的两个管道fd,不需要等子进程退出再关,进一步避免残留引用。

内容的提问来源于stack exchange,提问作者Mampac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 22:57:01