linux学习——管道

这篇文章简单介绍一下操作系统中的管道,并主要解决以下两个问题:

1、管道的内部实现

2、管道的容量?

管道是操作系统中,不同进程之间进行通信的方式。

根据通信的进程之间的关系,管道分为匿名管道和非匿名管道

其中,匿名管道只能用于有“血缘关系”的进程之间进行通信,而命名管道则可以用于任意两进程的通信

此外,管道是单向的,所以2个管道就可以实现进程之间的双向通信

管道的实现原理:

我们知道,进程之间的数据是私有的,即使是父子进程,也是如此,所以,要想让2个进程共享某个数据,我们可以在指定的路径下创建一个文件,然后其中一个进程将要传输的数据写入这个文件,另一个进程读取这个文件的信息,就可以实现进程之间的通信了,当然,考虑到效率,这一切通常是不可能发生在磁盘上的。

此外,由于一些机制,管道提供“流式”服务,对具体一次写入多少数据,一次读取多少数据,都不需要严格的规定

在Linux下,管道的实现没有使用专门的数据结构,而是借助了文件系统的file结构和VFS的索引节点inode。

通过两个file结构指向同一个临时的VFS索引节点,而这个VFS索引节点又指向一个物理页面而实现的。

如下图:

上图中有两个file数据结构,但他们定义文件操作例程地址是不同的,其中一个是向管道中写入数据的例程地址,另一个是从管道中读取数据d例程地址。

这样,用户程序系统调用仍然是通常的文件操作,而内核却利用这种抽象机制实现了管道这一特殊的操作。

//inode结点信息结构
struct inode {
...
    struct pipe_inode_info  *i_pipe;
... 
};

//管道缓冲区个数
#define PIPE_BUFFERS (16)
//管道缓存区对象结构
struct pipe_buffer {
    struct page *page; //管道缓冲区页框的描述符地址
    unsigned int offset, len; //页框内有效数据的当前位置,和有效数据的长度
    struct pipe_buf_operations *ops; //管道缓存区方法表的地址
};

//管道信息结构
struct pipe_inode_info {
    wait_queue_head_t wait; //管道等待队列
    unsigned int nrbufs, curbuf; //包含待读数据的缓冲区数和包含待读数据的第一个缓冲区的索引
    struct pipe_buffer bufs[PIPE_BUFFERS]; //管道缓冲区描述符数组
    struct page *tmp_page; //高速缓存区页框指针
    unsigned int start;  //当前管道缓存区读的位置
    unsigned int readers; //读进程的标志,或编号
    unsigned int writers; //写进程的标志,或编号
    unsigned int waiting_writers; //在等待队列中睡眠的写进程的个数
    unsigned int r_counter; //与readers类似,但当等待写入FIFO的进程是使用
    unsigned int w_counter; //与writers类似,但当等待写入FIFO的进程时使用
    struct fasync_struct *fasync_readers; //用于通过信号进行的异步I/O通知
    struct fasync_struct *fasync_writers; //用于通过信号的异步I/O通知
};

至于上文提到的VFS对象,在linux2.6以后的版本中,把这些对象组织成pipfs特殊文件系统以加速它们的处理

管道的容量:

如果管道被写满了,这时候写端就不会向管道再继续写入数据了

那么管道的容量具体是多大呢?

实际使用中,还有两个概念对理解管道至关重要。一个是管道容量。另一个是管道操作原子性。
管道容量有限。如果管道满,阻塞方式下write操作会阻塞,非阻塞方式下会返回失败。不同的系统有不同的管道容量限制。应用模块不应该依赖特定 的容量限制,正确的设计是:一旦数据到达进程应尽快消费数据,避免写进程长时间阻塞。从linux 2.6.11版本开始,管道容量是65536字节。
POSIX 1-2001规定向管道写小于PIPE_BUF字节长度的数据时原子操作;写超过PIPE_BUF字节长度的数据不是原子操作。Linux上PIPE_BUF是4096字节,更细致的描述:
1、阻塞方式,n<=PIPE_BUF(n为写入的字节数,下同):写操作是原子操作,如果pipe空间不足则阻塞。
2、非阻塞方式,n<=PIPE_BUF:写操作是原子操作,如果pipe空间不足,则失败,errno设置为EAGAIN。
3、阻塞方式,n>PIPE_BUF:写操作不是原子操作,写入的数据可能与其他进程写入的交叉排列,写操作阻塞直到所有数据写完。
4、非阻塞方式,n>PIPE_BUF:写操作不是原子操作,如果pipe空间不足,则失败,errno设置为EAGAIN。写入的数据可能与其他进程写入的数据交叉排列。同时实际写入可能小于n(部分写入);调用者应该检查write实际写入的长度。
三个概念:
1、页缓冲区大小:4K
2、总缓冲区大小:64K
1、<4K的数据立即发送,以页为单位
2、>4K的数据,将会分成多个页的数据,分批发送。
函数 write要么阻塞,要么成功(copy全部数据到内核缓冲区,不存在只copy部分数据的情况),异常换回-1

参考:

http://www.cppblog.com/aaxron/archive/2014/03/24/206312.aspx

(linux管道容量的测试)

http://blog.sina.com.cn/s/blog_629b701e0100zrk3.html

(linux管道的实现机制)

时间: 2024-10-05 07:05:07

linux学习——管道的相关文章

Linux学习之标准IO 管道 033_7

默认输入为键盘,标准输出为显示器,错误输出为显示器 把标准输出和错误输出重定向到文件: command operator filename operators: >:标准输出重定向 :把ls -R的输出重定向到文件 2>:错误输出重定向 &>:将正确和错误的输出都重定向 同时将正确和错误信息分别导入到不同文件: 以上默认覆盖,如果在文件末尾添加则用>>s 把错误输出重定向到空设备,也就是忽略错误信息 管道: 将前面一条命令执行的结果作为后面一条命令的输入 如: ls

Linux学习第五节课-标准I/O和管道

Linux学习第五节课 ------------------------------------------------------------------------------------------------------------------------------------------------------------------ 三十一.标准输入和输出 程序:指令+数据 读入数据:Input 输出数据:Output 打开的文件都有一个fd: file descriptor (文

linux 学习总结

下列是linux学习的基本知识点梳理: Vim编辑器 vi:visual interface 模式化: 编辑模式:命令模式 输入模式 末行模式 编辑模式-->输入模式 i:insert a:append o:new line I:行首 A:行尾 O:新建上方 编辑模式-->输入模式 ESC 编辑模式-->末行模式 : 末行模式-->编辑模式 ESC 打开Vim vim vim  /path/to/somewhere +# :#为行号 关闭vim :q  直接退出 :q! 强制退出

linux学习之进程,线程和程序

                                                                                  程序.进程和线程的概念 1:程序和进程的差别 进程的出现最初是在UNIX下,用于表示多用户,多任务的操作系统环境下,应用程序在内存环境中基本执行单元的概念.进程是UNIX操作系统环境最基本的概念.是系统资源分配的最小单位.UNIX操作系统下的用户管理和资源分配等工作几乎都是操作系统通过对应用程序进程的控制实现的! 当使用c c++ j

linux 学习基本知识

转自:http://blog.sina.com.cn/s/blog_55465b470100kixw.html 1.linux分区--在linux里面所有的设备.任何东西,在linux看来都是文件.--文件在它看来,有两种形式:  第一种是字符型(键盘输入.打印机):  第二种是二进制型(硬盘.光驱.U盘)--linux中所有硬件--手动分区--A.至少有两个分区  /    根分区  SWAP 交换分区(物理内存大小的两倍)--B.个人桌面分区  /  /boot 128MB is enoug

linux学习之路之bash及其特性

我们知道当我们用鼠标点击,或输入一个命令,系统就玩帮我们完成一个任务,那么当我们点击一个链接时,系统由是如何知道要去完成相应的操作呢?这是因为通过shell来完成的. 那么什么是shell呢? shell就是用户和操作系统之间的一个接口,通过这个接口shell接受来自用户的命令,并调用相应的应用程序来呼叫kernel来处理相应的工作. 在linux系统上面存放着多种类型的shell,这些shell存放在/etc/shells文件里,默认RedHat使用的shell为bash 下面介绍一些bash

(转)Linux学习要点(转载自红联)

Linux学习要点(转载自红联) 一.学习Linux的基本要求1. 掌握至少50个以上的常用命令. 2. 熟悉Gnome/KDE等X-windows桌面环境操作 . 3. 掌握.tgz..rpm等软件包的常用安装方法 4. 学习添加外设,安装设备驱动程序(比如网卡) 5. 熟悉Grub/Lilo引导器及简单的修复操作 . 6. 熟悉Linux文件系统 和目录结构. 7. 掌握vi,gcc,gdb等常用编辑器,编译器,调试器 . 8. 理解shell别名.管道.I/O重定向.输入和输出以及shel

linux学习之路之日志系统

日志系统 日志系统是用来存放系统在执行任务过程中产生的讯息或者是执行时产生的错误日志信息都存放在日志系统里.由于Linux系统上面会同时开启多个服务或者子系统,因此为了便于查看或者管理它们产生的日志信息,我们一般将不同的子系统或者服务产生的日志信息根据级别不同放在不同的配置文件中或者主机中. 在RHEL 5上,使用的日志系统是syslog 而在RHEL 6上,使用的日志系统是syslog-ng这是一款开源系统 要想使用syslog日志系统,必须要确保syslog服务一直在运行.而syslog服务

Linux学习4

1.Linux严格区分大小写,以点开头的文件是隐藏文件,比如说.abc. 2.Linux的文件类型:Linux的文件是以存储的类型来区别的,与后缀名无关. (1)普通文件, -,f (2)目录文件, d (3)链接文件, 符号链接:l 硬连接: - (4)特殊文件:作为硬件设备访问入口的文件 块设备:随机,按块进行存取 b 字符设备:线性,逐个按字符进行存取(键盘)   c (5)套接字文件socket,  s (6)命名管道pipe,   p 3.ls命令 (1) -l   l是long的意思