【问题标题】:Linux Pipes as Input and OutputLinux 管道作为输入和输出
【发布时间】:2010-12-16 15:16:01
【问题描述】:

我想在 Linux 操作系统上的 C 程序中执行以下操作:

  • 使用系统调用(或 2 个)创建 PIPE
  • 使用 exec() 执行新进程
  • 将进程的 STDIN 连接到之前创建的管道。
  • 将进程的输出连接到另一个 PIPE。

这个想法是为了性能目的而规避任何驱动器访问。

我知道使用 PIPE 系统调用创建管道非常简单 并且我可以使用 popen 来创建用于输入或输出目的的管道。

但是您将如何对输入和输出执行此操作?

【问题讨论】:

    标签: c linux ipc pipe


    【解决方案1】:

    根据您的需要,您可能会发现使用 mkfifo(1) 来创建命名管道并让您的进程读/写该文件会更容易。虽然文件是在文件系统中命名的,但使用匿名管道的开销不应该是可观的。

    【讨论】:

    • 在问题的上下文中,必须有两个单独的 FIFO,一个用于与子节点的通信,一个用于与子节点的通信。而且您必须担心程序的并发执行-使用什么名称-并且您必须担心之后(或程序崩溃时)清理 FIFO。嗯,FIFO的优点是什么?
    • 所以我说要看需要。根据 OP 的情况,可能根本不需要编写任何代码,特别是因为他说他想 exec(3)。
    【解决方案2】:

    你需要非常小心管道:

    1. 调用 pipe() 两次,一次用于 pipe-to-child,一次用于 pipe-from-child,产生 4 个文件描述符。
    2. 调用 fork()。
    3. 儿童:
      • 在标准输入(文件描述符 0)上调用 close()。
      • 调用 dup() - 或 dup2() - 将管道到子节点的读取端变为标准输入。
      • 在子管道的读取端调用 close()。
      • 在 pipe-to-child 的写入端调用 close()。
      • 在标准输出(文件描述符 1)上调用 close()。
      • 调用 dup() - 或 dup2() - 将子管道的写端写入标准输出
      • 在子管道的写入端调用 close()。
      • 在子管道的读取端调用 close()。
      • 执行所需的程序。
    4. 在父级中:
      • 在管道到子节点的读取端调用 close。
      • 在子管道的写入结束时调用 close。
      • 在子管道的写入端循环向子节点发送数据,并在子管道的读取端从子节点读取数据
      • 当不再发送给孩子时,关闭管道到孩子的写入端。
      • 收到所有数据后,关闭子管道的读取端。

    注意有多少关闭,尤其是在孩子中。如果使用 dup2(),则不必显式关闭标准输入和输出;但是,如果您执行显式关闭,则 dup() 可以正常工作。另请注意, dup() 和 dup2() 都不会关闭重复的文件描述符。如果您省略关闭管道,则两个程序都无法正确检测到 EOF;当前进程仍然可以写入管道的事实意味着管道上没有EOF,程序将无限期挂起。

    请注意,此解决方案不会改变孩子的标准误差;它与父级的标准错误位于同一位置。通常,这是正确的。如果您有特定要求以不同方式处理来自子级的错误消息,那么也要对子级的标准错误采取适当的措施。

    【讨论】:

    • 感谢您的回答。因此,理论上为解决方案生成了 2 个额外的过程。一个用于孩子,另一个用于外部二进制文件本身。在这种情况下,预期的性能会怎样?是否存在“单一过程”解决方案?使用这样的解决方案会有所收获吗?
    • exec() 替换了分叉的孩子。避免 exec() 的替代方法是将子代码包含在父可执行文件中。相同的管道规则适用 - 只需将最终的“exec”系统调用替换为对处理函数的调用。
    【解决方案3】:

    最简单的方法可能是执行/bin/sh,这样您就可以使用熟悉的shell语法来指定管道并减轻所有复杂性。

    类似:

    execlp("sh", "-c", "cat /dev/zero | cat > /dev/null", NULL);
    

    【讨论】:

    • 在某些情况下,这可能会起作用 - 使用与上述管道不同的管道,它只会消耗 CPU。然而,这个问题描述了一个写给孩子并从孩子那里得到回复的过程;在您的示例中,第二只猫必须将其输出反馈给第一只猫。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 2022-10-18
    相关资源
    最近更新 更多