多管道C程序不起作用

Posted

技术标签:

【中文标题】多管道C程序不起作用【英文标题】:multi-pipe C program does not work 【发布时间】:2014-10-25 17:09:30 【问题描述】:

我决定编写一个简单的硬编码 c 程序来更好地理解管道的工作原理。 该程序有 3 个命令: 寻找 。 -name '.' | sed 's/.*\.// |排序

它适用于 1 个管道(如果我只使用 2 个命令),但它失败了 2 个管道(排序只是没有得到信息)。

我认为错误在 close 或 waitpid 中,但我已经尝试了所有方法(我能想到的),但仍然无法正常工作。我错过了什么? 我使用的信息:

Is it possible to have pipe between two child processes created by same parent (LINUX, POSIX)

http://www.quora.com/Unix/How-can-I-write-a-code-for-PIPE-in-C-shell-script-python

Implementation of multiple pipes in C

编辑: 命令写得没有错误。问题绝对不在他们身上(因为如果我只使用 1 个管道,他们就可以工作) 我的代码:

#include <errno.h>
#include <stdio.h>
#include <unistd.h>  

int main(int argc, char* argv[]) 


    pid_t test, test2, test3;
    int old_pipe[2];
    int new_pipe[2];


    //test command
    //char *argv1[] = "ls", "-1", "-h", NULL;
    char *argv1[] = "find", ".", "-name", "*.*",NULL;
    char *argv2[] = "sed", "s/.*\\.//", NULL;
    char *argv3[] = "sort", NULL;

    //creates a pipe
    pipe(old_pipe);
    pipe(new_pipe);

    test = fork();
    if(test == 0)
        dup2(old_pipe[1], 1);
        close(old_pipe[0]);

        execvp(argv1[0], argv1);
            perror("exec");
            return 1;
    

    test2 = fork();
    if(test2 == 0)
        dup2(old_pipe[0], 0);
        close(old_pipe[1]);
        dup2(new_pipe[1], 1);
        close(new_pipe[0]);

        execvp(argv2[0], argv2);
            perror("exec");
            return 1;
    


    test3 = fork();
    if(test3 == 0)
        dup2(new_pipe[0], 0);
        close(new_pipe[1]);

        execvp(argv3[0], argv3);
        perror("exec");
        return 1;
    

    close(old_pipe[0]);
    close(old_pipe[1]);

    close(new_pipe[0]);
    close(new_pipe[1]); 

    waitpid(test);
    waitpid(test2);
    waitpid(test3);

    return 0;

【问题讨论】:

我在编写自己的 system() 函数以及实现 | 管道概念时的第一个建议是使用函数来实现,这样更容易推理您的代码,而不是 3 个内联分支变得不清楚。将逻辑移出 main 并抽象它。 是的,关于拆分我的逻辑,你是 100% 正确的。但我只是想看看管道是如何工作的,在尝试以正确的方式实现它们之前,我陷入了这个简单的例子(我认为应该工作)。 关闭文件。执行find 的孩子的new_pipe 两端都打开了!在 dup2 之后,您应该关闭四个文件描述符。 【参考方案1】:

您的第三个 exec(开始“排序”)不会关闭 old_pipe[1] 并保持打开状态。 sed 将看不到 EOF 并保持活动状态。你应该很晚才打电话给pipe(2)

我建议调查/proc/&lt;pid&gt;/fd resp。使用lsof 查看打开了哪些文件描述符。例如。之后

    dup2(old_pipe[1], 1);
    close(old_pipe[0]);

如果不是1,你应该关闭old_pipe[1]

更多解释(如评论中所问):您的程序有

pipe(old_pipe);
pipe(new_pipe);

test = fork();
   /* --> 'find'; writes into old_pipe[1] */
test2 = fork();
   /* --> 'sed'; reads from old_pipe[0], writes into new_pipe[1] */
test3 = fork();
   /* --> 'sort'; reads from new_pipe[0] */

只要其输入 (old_pipe[0]) 处于打开状态,test2 程序就不会退出。因为这个管道对于test3 是有效的(它等待test2 完成),它会死锁。

在子分支中关闭 fds 并不会在父进程中关闭它们。

【讨论】:

有效!你能解释一下为什么我必须关闭 old_pipe[0] 即使我之前关闭它?因此,如果我有 5 个管道同时处于活动状态,我需要在每个孩子处关闭每个管道? 你应该做的是关闭所有你不会使用的东西。所以如果你创建一个管道然后fork,你应该在两个进程中关闭所有没用的东西。写入进程应该立即关闭读取部分,读取进程应该立即关闭管道的写入部分。请记住,描述符是跨叉子继承的,因此如果您在叉子之前打开某些内容,之后,两个进程将拥有初始描述符的正确副本。

以上是关于多管道C程序不起作用的主要内容,如果未能解决你的问题,请参考以下文章

带有连续管道的 grep 不起作用

多次分叉后写入管道不起作用

Blazor .NET 5 的 Azure CI 管道不起作用

运行 mkfifo 的程序不起作用

角度:limitTo 管道不起作用

日期范围在聚合管道中不起作用,但在 find() 中起作用