混淆 dup2()、exec() 和管道
Confusion with dup2(), exec() and pipes
我一直在努力理解涉及命令 dup2()
、exec()
和管道的概念。
我想要实现的目标:
Pipe the output of a program X to the input of a program Y.
一些基本的东西,比如 who | sort
with a parent and 2 children, where the children are responsible for executing the programs and the parent passing the programs to the children.
以下是我对管道不理解的地方:
P1) 管道被视为文件并且应该是单向的,但是是什么阻止我将一个管道用于多个单向通信通道?
因此,假设我有 pipe1
和三个具有管道的进程(P
- parent - C1
、C2
、children)通过分叉打开。所有这些进程都可以使用文件描述符。
假设我们做的一切都正确,关闭未使用的管道末端,P
现在向 C1
写入一些内容。 再次使用管道在 C1
和 C2
之间进行通信有什么问题?
就在写这个问题的时候,一个想法打动了我:当许多进程可能同时打开它(两个进程正在阻塞以获取读取)时,谁从中读取它是否存在问题,即系统无法确定谁想要读取写入其中的缓冲数据?如果是这样,这在系统中是如何实现的?
我真的很想理解这个概念,所以请多多包涵。
为了将这个问题应用到现实生活中,我正在处理一些伪代码:
P:
P
关闭 pipe1
不需要的读端
P
通过 pipe1
将程序参数 ('who') 发送到 C1
P
关闭写结束
P
等待children退出
C1:
C1
从pipe1
的读端读取参数
C1
dup2()
s 标准输出到 pipe1
的写入端
C1
关闭 pipe1
的两端(因为我们已经欺骗了它)
C1
execvp()
程序 ('who')
C2:
C2
dup2()
s 读取 pipe1
的末尾到 stdin
以便它获得将要执行的程序的输入
C2
关闭 pipe1
的两端
C2
等待来自 dup
ed pipe1
C1
stdin
的输入
C2
execvp()
s 程序 ('sort') 具有此输入
现在,如果我按照上面的描述去做,我就没有运气了。
但是,如果我引入另一个管道 pipe2
它看起来像这样:
P:
P
关闭不需要的管道 两端 pipe2
P
关闭 pipe1
不需要的读端
P
通过 pipe1
将程序参数 ('who') 发送到 C1
P
关闭写结束
P
等待children退出
C1:
C1
关闭 pipe2
的读取结束
C1
从pipe1
的读端读取参数
C1
dup2()
s 标准输出到 pipe2
的写入端
C1
关闭 pipe2
的写结束
C1
关闭了 pipe1
的两端——pipe2
、pipe1
在 child 中是多余的
C1
execvp()
程序 ('who')
C2:
C2
dup2()
s 读取 pipe2
的结尾到 stdin
C2
关闭 pipe1
的两端
C2
等待来自 dup
ed pipe2
C1
stdin
的输入
C2
使用此输入 执行程序 sort
管道不应在多个进程中重复使用的假设是否正确,因为系统可能不确定要向谁"serve"?或者还有其他原因吗?
管道主要是为一对一的交流而设计的——一位作者,一位 reader。虽然没有什么可以阻止您拥有尽可能多的 readers 和 writer,但这种行为通常使它不太有用,尤其是对于多个 readers:
- 从管道读取是一种破坏性操作:通过管道发送的每个字节都将恰好被 reader 中的一个读取,无论谁先获取它。如果你想广播一些信息,你需要使用不同的 IPC 机制或显式复制数据(如
tee
命令)。
- 如果有多个写入者,他们的写入会以某种不可预测的方式穿插。唯一的保证是大小
PIPE_BUF
或更小的写入是原子的。
- 如果写入者数量降为零,reader 会看到文件结束条件。
在您所描述的体系结构中,您有两个独立的通信通道:P 将 who
发送到 C1,C1 将 运行 的输出 who
命令发送到 C2 .在 shell 脚本中,这类似于
echo who | { read command; exec command; } | sort
with echo who
在原始进程中执行而不是在子进程中执行shell。
你的第一个提议不可行,因为没有办法说 P 的输出将转到 C1,而 C1 的输出将转到 C2。它仍然是同一个管道,因此 P 的输出可以转到 C2,而 C1 的输出可以返回到它自己,也可以是混合。
我一直在努力理解涉及命令 dup2()
、exec()
和管道的概念。
我想要实现的目标:
Pipe the output of a program X to the input of a program Y.
一些基本的东西,比如 who | sort
with a parent and 2 children, where the children are responsible for executing the programs and the parent passing the programs to the children.
以下是我对管道不理解的地方:
P1) 管道被视为文件并且应该是单向的,但是是什么阻止我将一个管道用于多个单向通信通道?
因此,假设我有 pipe1
和三个具有管道的进程(P
- parent - C1
、C2
、children)通过分叉打开。所有这些进程都可以使用文件描述符。
假设我们做的一切都正确,关闭未使用的管道末端,P
现在向 C1
写入一些内容。 再次使用管道在 C1
和 C2
之间进行通信有什么问题?
就在写这个问题的时候,一个想法打动了我:当许多进程可能同时打开它(两个进程正在阻塞以获取读取)时,谁从中读取它是否存在问题,即系统无法确定谁想要读取写入其中的缓冲数据?如果是这样,这在系统中是如何实现的?
我真的很想理解这个概念,所以请多多包涵。
为了将这个问题应用到现实生活中,我正在处理一些伪代码:
P:
P
关闭pipe1
不需要的读端
P
通过pipe1
将程序参数 ('who') 发送到 P
关闭写结束P
等待children退出
C1
C1:
C1
从pipe1
的读端读取参数
C1
dup2()
s 标准输出到pipe1
的写入端
C1
关闭pipe1
的两端(因为我们已经欺骗了它)C1
execvp()
程序 ('who')
C2:
C2
dup2()
s 读取pipe1
的末尾到stdin
以便它获得将要执行的程序的输入C2
关闭pipe1
的两端
C2
等待来自dup
edpipe1
C2
execvp()
s 程序 ('sort') 具有此输入
C1
stdin
的输入
现在,如果我按照上面的描述去做,我就没有运气了。 但是,如果我引入另一个管道
pipe2
它看起来像这样:
P:
P
关闭不需要的管道 两端pipe2
P
关闭pipe1
不需要的读端
P
通过pipe1
将程序参数 ('who') 发送到 P
关闭写结束P
等待children退出
C1
C1:
C1
关闭pipe2
的读取结束
C1
从pipe1
的读端读取参数
C1
dup2()
s 标准输出到pipe2
的写入端
C1
关闭pipe2
的写结束
C1
关闭了pipe1
的两端——pipe2
、pipe1
在 child 中是多余的
C1
execvp()
程序 ('who')
C2:
C2
dup2()
s 读取pipe2
的结尾到stdin
C2
关闭pipe1
的两端
C2
等待来自dup
edpipe2
C2
使用此输入 执行程序
C1
stdin
的输入
sort
管道不应在多个进程中重复使用的假设是否正确,因为系统可能不确定要向谁"serve"?或者还有其他原因吗?
管道主要是为一对一的交流而设计的——一位作者,一位 reader。虽然没有什么可以阻止您拥有尽可能多的 readers 和 writer,但这种行为通常使它不太有用,尤其是对于多个 readers:
- 从管道读取是一种破坏性操作:通过管道发送的每个字节都将恰好被 reader 中的一个读取,无论谁先获取它。如果你想广播一些信息,你需要使用不同的 IPC 机制或显式复制数据(如
tee
命令)。 - 如果有多个写入者,他们的写入会以某种不可预测的方式穿插。唯一的保证是大小
PIPE_BUF
或更小的写入是原子的。 - 如果写入者数量降为零,reader 会看到文件结束条件。
在您所描述的体系结构中,您有两个独立的通信通道:P 将 who
发送到 C1,C1 将 运行 的输出 who
命令发送到 C2 .在 shell 脚本中,这类似于
echo who | { read command; exec command; } | sort
with echo who
在原始进程中执行而不是在子进程中执行shell。
你的第一个提议不可行,因为没有办法说 P 的输出将转到 C1,而 C1 的输出将转到 C2。它仍然是同一个管道,因此 P 的输出可以转到 C2,而 C1 的输出可以返回到它自己,也可以是混合。