UNIX子进程之间的管道

10

我试图编写一个程序,它将产生任意数量的子进程,并在它们之间进行管道传输,就像命令行管道一样。在我的情况下,我正在尝试执行 "ls -l | more" 并将其输出到 stdout,然后使父进程继续执行更多的命令。

以下是我作为最小示例的代码:

int main (int argc, const char * argv[]) {
    int fd[2];
    pipe(fd); 
    chdir("/directory/with/lots/of/files");

    // Create one child process for more
    int pid = fork();
    if (pid == 0) {
        close(fd[1]);
        int ret = dup2(fd[0],0);
        if (ret < 0) perror("dup2");
        char *argv[10];
        argv[0] = "more";  argv[1] = NULL;
        execvp("more", argv);
    } 
    // Create another child process for ls
    int pid2 = fork();
    if (pid2 == 0) {
        int ret = dup2(fd[1],1);
        if (ret < 0) perror("dup2");
        char *argv[10];
        argv[0] = "ls";    argv[1] = "-l";   
        argv[2] = NULL;
        execvp("ls", argv);
    }

    // wait for the more process to finish
    int status;
    waitpid(pid, &status, 0);

    printf("Done!\n");
    return 0;
}

现在,当我执行程序(当然是在一个main()函数中)时,得到的输出比较多,这是预期的。我按下“d”翻页,按下“u”向上滚动,它似乎运行良好。但是当我到达底部时,它不像more那样退出,而是留下一行空白。Ctrl-C可以退出,但它会退出整个程序,意味着“Done!”行永远不会被打印。这里有一部电影(链接已失效)说明了发生了什么(请注意,在最后我按下Ctrl-C返回到bash)。

对此您有什么想法吗?我只是想弄清楚如何改变它,使得当more到达底部时,它会退出并返回到父进程,以便它可以继续执行。


检查more是否是指向less的符号链接。Less需要使用-e选项在文件末尾退出。您的程序环境中的PATH与交互式环境可能存在差异。 - Dennis Williamson
不是的,但还是谢谢你提醒我。这只是给了我一个额外的测试案例。 :) - jstm88
2个回答

11

你需要关闭管道的writing端口,否则more永远不会看到EOF(End of File)。例如:

    ...

    // close parent's pipes
    close(fd[0]);
    close(fd[1]);

    // wait for the more process to finish
    int status;
    waitpid(pid, &status, 0);

    printf("Done!\n");
    return 0;
}

在第一个子进程中的dup2()完成后,您还应该执行 close(fd[0]),对于第二个子进程也是同理操作 fd[1] - caf
1
太好了,成功了!我在子进程中关闭了管道(至少在最终版本中是这样的,我刚意识到第二个子进程的最小示例缺少close(fd[0]);),但我从未想过在父进程端关闭它们。深入研究后,我发现了评论“分叉后,您将拥有具有两个输入和两个输出的单个管道”,这在这种情况下是有意义的。谢谢!编辑:没错,caf,我在生产版本中关闭了它们。 :) - jstm88

-1

我认为这是由于wait()函数引起的。根据逻辑,你的第二个子进程输出到第一个子进程,这意味着它应该比第二个子进程先结束。

在你的wait函数中,你正在等待第一个进程结束,但你没有等待第二个进程。这意味着如果第二个进程永远不发送EOF到输出,你的第一个进程就不会结束,我猜。

你可以尝试等待第二个进程而不是第一个进程,看看是否有问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接