管道

来源:互联网 发布:出国翻译软件 编辑:程序博客网 时间:2024/06/08 12:15

一般的Linux shell程序都允许重定向。如

$ ls | pr | lpr

在这个管道应用中,ls列当前目录的输出被作为标准输入送到pr程序中,而pr的输出又被作为标准输入送到lpr程序中。管道是单向的字节流,它将某个进程的标准输出连接到另外进程的标准输入。但是使用管道的进程都不会意识到重定向的存在,并且其执行结果也不会有什么不同。shell程序负责在进程间建立临时的管道。


图5.1 管道

在Linux中,管道是通过指向同一个临时VFS inode的两个file数据结构来实现的,此VFS inode指向内存中的一个物理页面。图5.1中每个file数据结构指向不同的文件操作例程向量,一个是实现对管道的写,另一个从管道中读。

这样就隐藏了读写管道和读写普通的文件时系统调用的差别。当写入进程对管道写时,字节被拷贝到共享数据页面中,当读取进程从管道中读时,字节从共享数据页面中拷贝出来。Linux必须同步对管道的访问。它必须保证读者和写者以确定的步骤执行,为此需要使用锁、等待队列和信号等同步机制。

当写者想对管道写入时,它使用标准的写库函数。表示打开文件和打开管道的描叙符用来对进程的file数据结构集合进行索引。Linux系统调用使用由管道file数据结构指向的write过程。这个write过程用保存在表示管道的VFS inode中的信息来管理写请求。

如果没有足够的空间容纳对所有写入管道的数据,只要管道没有被读者加锁。则Linux为写者加锁,并把从写入进程地址空间中写入的字节拷贝到共享数据页面中去。如果管道被读者加锁或者没有足够空间存储数据,当前进程将在管道inode的等待队列中睡眠,同时调度管理器开始执行以选择其它进程来执行。如果写入进程是可中断的,则当有足够的空间或者管道被解锁时,它将被读者唤醒。当数据被写入时,管道的VFS inode被解锁,同时任何在此inode的等待队列上睡眠的读者进程都将被唤醒。

从管道中读出数据的过程和写入类似。

进程允许进行非阻塞读(这依赖于它们打开文件或者管道的方式),此时如果没有数据可读或者管道被加锁,则返回错误信息表明进程可以继续执行。阻塞方式则使读者进程在管道inode的等待队列上睡眠直到写者进程结束。当两个进程对管道的使用结束时,管道inode和共享数据页面将同时被遗弃。

Linux还支持命名管道(named pipe),也就是FIFO管道,因为它总是按照先进先出的原则工作。第一个被写入的数据将首先从管道中读出来。和其它管道不一样,FIFO管道不是临时对象,它们是文件系统中的实体并且可以通过mkfifo命令来创建。进程只要拥有适当的权限就可以自由使用FIFO管道。打开FIFO管道的方式稍有不同。其它管道需要先创建(它的两个file数据结构,VFS inode和共享数据页面)而FIFO管道已经存在,只需要由使用者打开与关闭。在写者进程打开它之前,Linux必须让读者进程先打开此FIFO管道;任何读者进程从中读取之前必须有写者进程向其写入数据。FIFO管道的使用方法与普通管道基本相同,同时它们使用相同数据结构和操作。