【发布时间】:2015-07-03 17:16:54
【问题描述】:
我一直在努力理解涉及命令dup2()、exec() 和管道的概念。
我想要达到的目标:
将程序 X 的输出连接到程序 Y 的输入。
who | sort 之类的基本内容
有一个父级和 2 个子级,其中子级负责执行程序,而父级将程序传递给子级。
这是我对管道的不理解:
P1) 管道被视为文件,应该是单向的,但是是什么阻止我使用一个管道进行多个单向通信通道?
所以,假设我有pipe1 和三个进程(P - 父级 - C1、C2、子级)通过分叉打开管道。所有这些进程都可以使用文件描述符。
假设我们一切正常,关闭未使用的管道末端,P 现在向C1 写入一些内容。 再次使用管道在C1 和C2 之间进行通信有什么问题?
就在写这个问题的时候,我突然想到一个想法:谁读取它有问题,而许多进程可能同时打开它(两个进程阻塞读取),即系统无法确定谁想读取写入其中的缓冲数据?如果是这样,这是如何在系统中实现的?
我真的很想理解这个概念,所以请多多包涵。
为了将这个问题应用到现实生活中,我正在处理一些伪代码:
亲:
-
P关闭pipe1的不需要的读取端 -
P通过pipe1将程序参数('who')发送到C1 -
P关闭写端 -
P等待孩子退出
C1:
-
C1从pipe1的读取端读取参数 -
C1dup2()s 标准输出到pipe1的写入端 -
C1关闭pipe1的两端(因为我们已经欺骗了它) -
C1execvp()s 程序(“谁”)
C2:
-
C2dup2()s 将pipe1的结尾读取到stdin以便它获取将要执行的程序的输入 -
C2关闭pipe1的两端 -
C2等待来自dupedpipe1的C1的stdin上的输入 -
C2execvp()s 程序('排序')与此输入
现在,如果我按照上面描述的那样做,我就没有运气了。 但是,如果我引入另一个管道
pipe2,它看起来像这样:
亲:
-
P关闭不需要的管道的两端pipe2 -
P关闭pipe1的不需要的读取端 -
P通过pipe1将程序参数('who')发送到C1 -
P关闭写端 -
P等待孩子退出
C1:
-
C1关闭pipe2的读取结束 -
C1从pipe1的读取端读取参数 -
C1dup2()s 标准输出到pipe2的写端 -
C1关闭pipe2的写结束 -
C1关闭了pipe1的两端——在这个孩子中pipe2、pipe1是多余的 -
C1execvp()s 程序('谁')
C2:
-
C2dup2()s 读取pipe2的结尾到stdin -
C2关闭pipe1的两端 -
C2等待来自dupedpipe2的C1的stdin上的输入 -
C2使用此输入执行程序sort
不应该在多个进程中重用管道的假设是否正确,因为系统可能不确定要“服务”谁?或者还有其他原因吗?
【问题讨论】:
-
你能详细说明一下吗?我是否正确理解这种情况:P 以某种方式接收到
a | b之类的输入,然后创建 C1 和 C2,C1 执行 a,C2 执行 b。 a 的标准输出应该是 b 的标准输入。我对么?这是一个要求吗? P不能只分叉C1,C1可以分叉C2吗? -
另外,
execfamily 在指定操作后不会继续,所以 C1 和 C2 将在命令后终止。这意味着每当 P 收到像a | b这样的新输入时,它都必须再次分叉。既然如此,P 和 C1 以及 P 和 C2 之间的通信在这里似乎是多余的。 -
@holgac 是的,你是完全正确的。这是一个要求。我会知道如何按照你所说的方式把它拉下来。
-
是的,我知道
exec()替换了当前进程。家长需要将程序传达给孩子,这是一项要求。 -
那么正如 Gilles 在他/她的回答中所说,你不能那样做。单向管道意味着读/写端使用相同的缓冲区。相反,您需要在 P 和 C1 之间有一个管道 (p1),在 P 和 C2 之间有另一个管道 (p2),在 C1 和 C2 之间有另一个 (p3)。由于 C1 和 C2 是兄弟姐妹,因此它们无法创建每个人都可以共享的管道。您需要在 C1 之前创建 p1,在 C2 之前创建 p2,在 C1 和 C2 之前创建 p3。