next up previous contents
下一主题: 6.2.2 在 中创建管道 上一层: 6.2 半双工 UNIX 管道 前一主题: 6.2 半双工 UNIX 管道

6.2.1 基本概念

简而言之,管道是一种将一个进程的标准输出连接到另一个进程的标准输入的方法。管道是最古老的 IPC 工具之一,自 UNIX 操作系统的最早版本就已存在。它们提供了一种进程之间单向通信(因此称为半双工)的方法。

这个特性被广泛使用,即使在 UNIX 命令行(shell)中也是如此。

        ls | sort | lp

以上代码建立了一个管道线,将 ls 的输出作为 sort 的输入,并将 sort 的输出作为 lp 的输入。数据通过半双工管道传输,(视觉上)从左到右穿过管道线。

尽管我们大多数人在 shell 脚本编程中非常频繁地使用管道,但我们常常这样做时并没有仔细考虑内核级别发生了什么。

当一个进程创建一个管道时,内核会设置两个文件描述符供管道使用。一个描述符用于允许数据输入管道(写入),而另一个描述符用于从管道获取数据(读取)。此时,管道的实际用途不大,因为创建进程只能使用管道与自身通信。考虑一下进程和内核在创建管道后的这种表示

picture41666

从上面的图中,很容易看出描述符是如何连接在一起的。如果进程通过管道(fd0)发送数据,它有能力从 fd1 获取(读取)该信息。然而,上面简图的目的是更大的。虽然管道最初将进程连接到自身,但通过管道传输的数据会穿过内核。特别是在 Linux 中,管道实际上在内部用有效的 inode 表示。当然,这个 inode 驻留在内核本身内部,而不是任何物理文件系统的界限内。这个特别的点将为我们打开一些非常方便的 I/O 大门,我们稍后会看到。

此时,管道相当无用。毕竟,如果只是要和自己对话,为什么要费力创建管道呢?此时,创建进程通常会 fork 一个子进程。由于子进程将继承父进程的任何打开的文件描述符,我们现在就有了多进程通信(在父进程和子进程之间)的基础。考虑一下我们简单草图的这个更新版本

picture41666

上面,我们看到两个进程现在都可以访问构成管道线的文件描述符。在这个阶段,必须做出一个关键的决定。我们希望数据朝哪个方向传输?是子进程向父进程发送信息,还是反之亦然?这两个进程就这个问题达成一致,并继续“关闭”它们不关心的管道端。为了讨论的目的,假设子进程执行一些处理,并通过管道将信息发送回父进程。我们新修订的草图将如下所示

picture44468

管道线的构建现已完成!剩下的唯一事情就是使用管道。要直接访问管道,可以使用与低级文件 I/O 相同的系统调用(回想一下,管道实际上在内部表示为有效的 inode)。

要向管道发送数据,我们使用 write() 系统调用,要从管道检索数据,我们使用 read() 系统调用。请记住,低级文件 I/O 系统调用与文件描述符一起工作!但是,请记住,某些系统调用,例如 lseek(),不适用于管道的描述符。


next up previous contents
下一主题: 6.2.2 在 中创建管道 上一层: 6.2 半双工 UNIX 管道 前一主题: 6.2 半双工 UNIX 管道

转换于
Fri Mar 29 14:43:04 EST 1996