We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
目录
假如我们在 shell 终端执行以下命令:
$ ls | wc -l
该命令的作用是计算当前目录中文件的个数。这其实是由两个命令组成:ls 和 wc -l,前者是列出当前目录下的文件名,后者是计算一个给定文件中的字符行数。
ls
wc -l
可以推测其执行逻辑如下:ls 把列出的文件名按行写入到一个文件,然后 wc 从该文件中逐行统计行数,于是就得到了当前目录下的文件数目。
实际上将 ls 列出的文件名写入到的文件就是管道,组合命令 ls | wc - l 的原理就是通过 fork 为 ls 和 wc 各生成一个子进程并通过管道进行通。管道是 Unix 下最古老的跨进程通信方式。
ls | wc - l
管道不存在消息和消息边界的概念,从管道中读取数据的进程可以读取任意大小的数据块,而不管写入进程写入管道的数据块的大小是多少。管道中的数据是有序的,读出的字节顺序和写入的字节顺序保持一致。不能通过 lseek 系统调用对管道中的字节流进行随机访问。
管道本质上是一个 内核 内存中维护的 缓冲器,该缓冲器有一个有限的初始容量,一般来说,该容量一般 ≥ 4096 字节。
试图从一个空管道中读取数据将会被阻塞直到至少有一个字节被写入管道中为止。如果管道的写入端被关闭了,那么从管道中读取数据的进程在读完管道中剩余的所有数据之后将会看到文件结束(即 read()返回 0)。
如果管道中的数据已经达到其容量限制,后续向该管道的写入操作就会被阻塞直到读者进程从管道中移除一些数据为止。
在管道中数据的传递方向是单向的。管道的一端用于写入,另一端用于读取。
创建一个管道由 pipe 系统调用来完成:
int pipe(int filedes[2]);
调用成功后,会在返回参数 filedes 中返回两个文件描述符:filedes[0] 用于管道的读取端,filedes[1] 用于管道的写入端。
filedes[0]
filedes[1]
由于是文件描述符,所以可以按照文件描述符的统一操作来在 filedes[0] 和 filedes[1] 上使用 read() 和 write() 系统调用来在管道上执行 I/O。
但是管道一般是用于在多个 相关进程 中进行通信的。这里的相关进程是指有继承关系的进程或者有相同祖先的兄弟进程等。当然在少数情况下也可能是在同一个进程的不同线程间使用(比如 Android 的 Looper 事件通知机制)。
之所以要在相关进程中使用管道,是因为在一个进程上创建管道后,需要将管道的两个文件描述符传递给通信双方的进程。假如是两个不相关的进程,就需要通过另外一种 IPC 方式把文件描述符先传递过去。而如果是相关进程间通信,比如是父子进程,就可以是父进程创建管道,然后通过 fork 一个子进程,子进程把管道的两个文件描述符都继承了过去,这样无需通过三方 IPC 手段进行文件描述符传递了。又比如是兄弟进程间通信,可以通过共同的祖先进程创建管道,然后兄弟进程都共享了该管道的两个文件描述符,从而可以进行通信。
另外,通常情况下,一个进程只负责对管道进行读,另一个进程只负责对管道进行写。当一个进程拥有一个管道的两个文件描述符之后,需要将未使用的文件描述符关闭,这样做的原因如下:
以下为父子进程间使用管道的的图例:
Linux-Unix系统编程手册(第44章)
The text was updated successfully, but these errors were encountered:
No branches or pull requests
目录
1 一个典型场景[Top]
假如我们在 shell 终端执行以下命令:
$ ls | wc -l
该命令的作用是计算当前目录中文件的个数。这其实是由两个命令组成:
ls
和wc -l
,前者是列出当前目录下的文件名,后者是计算一个给定文件中的字符行数。可以推测其执行逻辑如下:ls 把列出的文件名按行写入到一个文件,然后 wc 从该文件中逐行统计行数,于是就得到了当前目录下的文件数目。
实际上将 ls 列出的文件名写入到的文件就是管道,组合命令
ls | wc - l
的原理就是通过 fork 为 ls 和 wc 各生成一个子进程并通过管道进行通。管道是 Unix 下最古老的跨进程通信方式。2 管道要点[Top]
管道不存在消息和消息边界的概念,从管道中读取数据的进程可以读取任意大小的数据块,而不管写入进程写入管道的数据块的大小是多少。管道中的数据是有序的,读出的字节顺序和写入的字节顺序保持一致。不能通过 lseek 系统调用对管道中的字节流进行随机访问。
管道本质上是一个 内核 内存中维护的 缓冲器,该缓冲器有一个有限的初始容量,一般来说,该容量一般 ≥ 4096 字节。
试图从一个空管道中读取数据将会被阻塞直到至少有一个字节被写入管道中为止。如果管道的写入端被关闭了,那么从管道中读取数据的进程在读完管道中剩余的所有数据之后将会看到文件结束(即 read()返回 0)。
如果管道中的数据已经达到其容量限制,后续向该管道的写入操作就会被阻塞直到读者进程从管道中移除一些数据为止。
在管道中数据的传递方向是单向的。管道的一端用于写入,另一端用于读取。
3 管道的创建和使用[Top]
创建一个管道由 pipe 系统调用来完成:
调用成功后,会在返回参数 filedes 中返回两个文件描述符:
filedes[0]
用于管道的读取端,filedes[1]
用于管道的写入端。由于是文件描述符,所以可以按照文件描述符的统一操作来在
filedes[0]
和filedes[1]
上使用 read() 和 write() 系统调用来在管道上执行 I/O。但是管道一般是用于在多个 相关进程 中进行通信的。这里的相关进程是指有继承关系的进程或者有相同祖先的兄弟进程等。当然在少数情况下也可能是在同一个进程的不同线程间使用(比如 Android 的 Looper 事件通知机制)。
之所以要在相关进程中使用管道,是因为在一个进程上创建管道后,需要将管道的两个文件描述符传递给通信双方的进程。假如是两个不相关的进程,就需要通过另外一种 IPC 方式把文件描述符先传递过去。而如果是相关进程间通信,比如是父子进程,就可以是父进程创建管道,然后通过 fork 一个子进程,子进程把管道的两个文件描述符都继承了过去,这样无需通过三方 IPC 手段进行文件描述符传递了。又比如是兄弟进程间通信,可以通过共同的祖先进程创建管道,然后兄弟进程都共享了该管道的两个文件描述符,从而可以进行通信。
另外,通常情况下,一个进程只负责对管道进行读,另一个进程只负责对管道进行写。当一个进程拥有一个管道的两个文件描述符之后,需要将未使用的文件描述符关闭,这样做的原因如下:
以下为父子进程间使用管道的的图例:
参考[Top]
Linux-Unix系统编程手册(第44章)
The text was updated successfully, but these errors were encountered: