与dup2(),exec()和管道

时间:2015-04-24 22:42:08

标签: c unix pipe exec dup2

我一直在努力理解涉及命令dup2()exec()和管道的概念。

我想要实现的目标:

  

将程序X的输出传送到程序Y的输入。

who | sort

这样的基本内容
  

有一个父级和 2 子级,其中子级负责执行程序,父级将程序传递给子级。

以下是我对管道无法理解的内容:

P1)管道被视为文件,应该是单向的,但是什么阻止我将一个管道用于多个单向通信通道?  所以,让我们说我有pipe1和三个流程(P - 父 - C1C2,孩子们)通过分叉打开管道。所有这些进程都可以使用文件描述符。 假设我们正在正确地完成所有操作,关闭未使用的管道末端,P现在将内容写入C1使用管道在C1C2之间再次进行通信有什么问题? 在写这个问题的时候,一个想法让我感到困惑:是否存在谁从中读取数据的问题,而许多进程可能同时打开它(两个进程阻塞以获取读取),即系统无法确定谁想要读取写入的缓冲数据?如果是这样,如何在系统中实现?

我真的很想了解这个概念,所以请耐心等待。

要将这个问题应用到现实生活中,这里有一些我正在处理的伪代码:

,P:

  • P关闭pipe1
  • 不需要的阅读结尾
  • P通过C1
  • pipe1发送计划参数('谁')
  • P关闭了写结束
  • P等待孩子退出

C1:

  • C1pipe1
  • 的读取结尾读取参数
  • C1 dup2()pipe1
  • 写入结束的标准输出
  • C1关闭了pipe1的两端(因为我们已经将其欺骗了)
  • C1 execvp()该计划(' who')

C2:

  • C2 dup2()读取pipe1stdin的结尾,以便获取将要执行的程序的输入
  • C2关闭了pipe1
  • 的两端
  • C2等待来自stdin ed C1
  • dup pipe1的输入 使用此输入
  • C2 execvp()的程序(' sort')

<小时/> 现在,如果我按照上面的描述去做,我就没有运气了。 但是,如果我引入了另一个管道pipe2,它看起来像这样: 的,P:

  • P关闭不需要的管道pipe2两端
  • P关闭pipe1
  • 不需要的阅读结尾
  • P通过C1
  • pipe1发送计划参数(&#39;谁&#39;)
  • P关闭了写结束
  • P等待孩子退出

C1:

  • C1关闭pipe2
  • 的阅读结尾
  • C1pipe1
  • 的读取结尾读取参数
  • C1 dup2()pipe2
  • 写入结束的标准输出
  • C1关闭pipe2
  • 的结束
  • C1关闭了pipe1的两端 - pipe2pipe1在这个孩子中多余了
  • C1 execvp()该计划(&#39; who&#39;)

C2:

  • C2 dup2()读取pipe2stdin
  • 的结尾
  • C2关闭了pipe1
  • 的两端
  • C2等待来自stdin ed C1
  • dup pipe2的输入
  • C2使用此输入执行程序sort

假设管道不应该在多个流程中重复使用,因为系统可能无法确定管理员是否需要服务&#34; ?或者还有其他原因吗?

1 个答案:

答案 0 :(得分:2)

管道主要用于一对一通信 - 一个作家,一个读者。虽然没有什么可以阻止你拥有尽可能多的读者和作者,但这种行为常常使得它不是很有用,特别是对于多个读者:

  • 从管道中读取是一种破坏性的操作:通过管道发送的每个字节将由一个读取器读取,无论谁先抓取它。如果要广播某些信息,则需要使用不同的IPC机制或显式复制数据(如tee命令)。
  • 如果有多个作者,他们的写作会以某种不可预测的方式穿插。唯一的保证是大小为PIPE_BUF或更小的写入是原子的。
  • 如果写入者数量降至零,则读者会看到文件结束条件。

在您描述的体系结构中,您有两个独立的通信通道:P将who发送到C1,C1将运行who命令的输出发送到C2。在shell脚本中,这类似于

echo who | { read command; exec command; } | sort

echo who在原始流程中执行,而不是在子shell中执行。

你的第一个提案不起作用,因为没有办法说P的输出将转到C1并且C1的输出将转到C2。它仍然是同一个管道,所以P的输出可以转到C2,C1的输出可以回到自身,或者它可能是混合物。