【问题标题】:Is it possible to have pipe between two child processes created by same parent (LINUX, POSIX)是否可以在同一父级(LINUX,POSIX)创建的两个子进程之间建立管道
【发布时间】:2011-07-10 16:40:39
【问题描述】:

我有多个子进程由同一个父进程“分叉”,我尝试在所有这些子进程之间构建pipe 连接,如链表结构。孩子 1 向孩子 2 发送数据,孩子 2 向孩子 3.... 孩子 N 向孩子 1 发送数据。有什么合适的方法吗?

此外,如果我在进程之间创建和通信,我如何强制父进程“等待”所有进程以完成他们的工作,因为 wait()waitpid() 等待第一个完成的进程,但我需要等待所有进程。这是另一个问题。

谢谢...

【问题讨论】:

    标签: c linux ipc pipe


    【解决方案1】:

    首先创建所有管道,然后在 FD 0 和 1 中生成所有具有适当管道末端的子节点。

    至于等待,一直等到它返回-1。

    【讨论】:

    • 我没有得到“一直等到它返回 -1”。你的意思是?您的意思是“等待(-1);”还是什么?
    • 继续循环调用它,直到它返回-1。
    【解决方案2】:

    这本质上是shell在构建重定向链时所做的事情,即类似

    ls | grep foo | sort | uniq
    

    有一些关于 Unix 编程的优秀介绍性文本,其中通过本书实现了一个简单的 shell。 shell 的任务之一是重定向。其中一本书是 Michael K. Johnson 和 Erik W. Troan 的《Linux 应用程序编程》。

    本书首页:http://ladweb.net/

    要为 N 个进程构建一个重定向链,您需要 N-1 个管道。对于每个重定向,您使用pipe(int fds[2]) 系统调用创建一个管道。在fork()ing 之后,但在execving 之前使用dup2(int from, int to) 将管道的末端“连接”到每个进程的标准输入(0)或标准输出。这是一个过于简化的代码,没有错误检查:

    int pipe_A[2];
    int pipe_B[2];
    
    pipe(pipe_A);
    pipe(pipe_B);
    
    pid_t pid_A, pid_B, pid_C;
    
    if( !(pid_A = fork()) ) {
        dup2(pipe_A[1], 1); /* redirect standard output to pipe_A write end */
        execv(...);
    }
    
    if( !(pid_B = fork()) ) {
        dup2(pipe_A[0], 0); /* redirect standard input to pipe_A read end */
        dup2(pipe_B[1], 1); /* redirect standard output to pipe_B write end */
        execv(...);
    }
    
    if( !(pid_C = fork()) ) {
        dup2(pipe_B[0], 0); /* redirect standard input to pipe_B read end */
        execv(...);
    }
    

    请注意,管道的数组索引的选择方式可以反映标准输入/输出文件描述符(如果它们用于 stdio 重定向)。这种选择不是任意的。

    当然,您可以将管道连接到任何文件描述符(例如,有些应用程序希望它们的父级打开,例如 fd 3 和 4,连接到管道)并且大多数 shell 也直接支持这一点(例如 1> &3 将标准输出重定向到 fd 3)。但是,pipe(int fds[2]) 的数组索引当然是 0 和 1。我只是这么说,因为我有一些狂热的编程学生,他们盲目地将目标 fds 也用于管道系统调用数组。

    等待所有子进程完成使用waitpid(-1, NULL, 0) - 我认为这是我的预回答者的意思 -1,这意味着:等待所有子进程完成。另一个选项是在循环中调用wait(),这将返回刚刚终止的孩子的pid。如果再次调用并且仍然有一个孩子在运行,它将再次阻塞。如果没有孩子,则返回-1;我更喜欢waitpid 解决方案。

    【讨论】:

    • 快速问题,当我使用上面的代码时,我的程序挂在第二个 execv 上,我认为它正在等待标准输入的 EOF。我是如何关闭标准输入的?
    • @TrewTzu:在标准输入被 dup2(pipe_A[0], 0) 替换后,您不能关闭它,因为它会关闭管道。我也不明白为什么 execv 应该阻止。但是 execv 不会返回,它用被调用的程序替换进程。这就是为什么这个过程是预先分叉的。你在哪个操作系统上尝试这个?只是古玩。
    • 这有点晚了,但是看看这段代码,后面的if语句不应该是“else if”吗?否则,第一个 fork 的子节点和父节点都将运行第二个。
    • @JacobSharf:不,因为exec… 替换了过程映像。 if 语句中exec… 之后的所有内容都不会执行。
    【解决方案3】:

    是的,这相当简单,您只需要在父级中创建所有管道,并记住关闭您不需要的子级中的管道/管道末端。

    在不使用它们的子进程中打开管道的 FD 是失败的,因为它会使其他人永远等待管道结束。所有写入器必须在读取器获得 EOF 之前关闭。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多