首页 > 解决方案 > 用一个循环和一个管道在 C 中实现无限管道

问题描述

我正在尝试构建一个 minishell,除了管道之外,我几乎什么都没有。我在这个网站和许多其他网站上阅读了很多答案,但我无法找到我的特定问题。

该序列应该在最右边的进程结束时结束,即:sleep 3 | sleep 3 | sleep 0应该立即结束,而不是等待任何 sleep 3 进程。

*argvv 是指向第一个进程的指针(*argvv 是sleep 3,*(argvv + 1) 是下一个sleep 3,等等。我不知道发生了什么,但是文件描述符有问题,测试后一切都中断了。

例如,当输入为 时sh> ls | wc | wc,输出为

sh> ls | wc | wc
sh>    1       3      25

,然后它等待一些输入。直到我再次按下回车它才完成。之后,sleep 3不再工作。

欢迎任何帮助,非常感谢!

编辑:

好的,我编辑了代码,一切似乎都正常,除了 sleep 3 | sleep 0 持续 3 秒,而不是立即结束。我不知道如何解决这个问题。

void execute(char ***argvv)
{
    pid_t pid;
    int pd[2];
    int in = 0;

    while (*argvv != NULL) {
        pipe(pd);
        
        if ((pid = fork()) < 0)
        {
            perror();
            exit(1);
        }
        else if (pid == 0) {
            dup2(in, 0);
            if (*(argvv + 1) != NULL)
                dup2(pf[1], 1);
            close(pd[0]);
            close(pd[1]);
            execvp((*argvv)[0], *argvv);
            perror();
            exit(1);
        }

        else
        {
            close(pd[1]);
            in = pd[0];

            if (*(argvv + 1) == NULL)
                close(pd[0]);
            argvv++;
        }
        wait(&pid);
    }

}

标签: cshellwhile-looppipeexecvp

解决方案


我认为部分问题可能在于使用wait(). 它的 pid 参数是一个 OUTPUT,报告哪个fork()ed 进程结束了。每个分叉的处理都结束了,需要对其进行wait()编辑。当您运行第二个管道时,除了前面的一个管道之外的所有其他管道仍然准备好进行wait()编辑。

通常,您有几种选择:

  1. wait()循环,直到您要结束的过程结束。
  2. wait()循环,直到所有子流程结束。
  3. 用于waitpid()查找特定的进程结束。
  4. 安排只有链中的最后一个进程是您的进程的子进程,使其余进程成为该进程的子进程。(这是由某个 shell 完成的,虽然我不记得是哪个。)这样做的问题是它为链中的最后一个进程留下了额外的子进程,这可能会使它感到困惑。
  5. 跟踪所有子进程,以及哪些已经结束。在后台运行管道时,这允许您显示管道的哪些部分仍在运行。(tcsh 做到这一点。bash 做到了一半。)
  6. fork()较早的管道成员两次,execvp()在孙子中,然后exit()在孩子中,并让孩子的父母wait()在继续之前完成。这将孙子与父级断开连接,因此永远不需要等待。
  7. 做涉及忽略的事情SIGCHLD,但这可能会给你带来很多悲伤,因为它要么全有,要么全无。

推荐阅读