管中窥道——我看Linux内核管道

来源:互联网 发布:网上企业信用数据库 编辑:程序博客网 时间:2024/05/16 14:59
 

管中窥道——记录Linux内核管道(2)

刺猬@http://blog.csdn.net/littlehedgehog

 





上节说了我对Linux管道的一点儿小见解,这节来看看内核中关于管道的实现代码。

  以下代码摘自 Linux/include/fs.h

#define PIPE_HEAD(inode) ((inode).i_zone[0])  //这里定义了管道头

 

#define PIPE_TAIL(inode) ((inode).i_zone[1])  //呃,这里定义的管道尾
 

管道的头尾我们都定义了,大家回头来看看管道的size 的定义:

 

#define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1)) 

这里用 (管道头-管道尾)%pagesize 取余数 从而取得了管道大小,关于这个取余数的问题,我在《求余不用模》 中已经详细阐释了这种方法的数学原理。但是这段代码最值得探讨的倒还不是这块内容。我们来看看管道的抽象图:

假设管道大小是4,(请注意管道大小必须要选择2n种形式),我们看看上图如果管头指针指向3,而管尾指针指向的是1,那么管道的大小按照上面的算法,我们得出管道大小为2 (即是(3-1)&3),那么我们有理由说上图管道头的指针指向的3号元素其实是空的!而我们不妨再假设如果是管头指向的是1,而管尾指向的是3,那么按照上面的做法(1-3)&3,最后得出的是2,注意这里虽然是负数但是用这种办法仍然奏效。

说了这么多,其实可能有人早就注意到了管道是个队列的数组结构,而且还是队列的一种特殊形式——循环队列。

对于这种队列,我们通常空出了一个元素位置来表达队列是否已满。比如如果rear==front 则表示管道为空,如果为满的话就不能还用这个表示了,(不然我们如何区分究竟谁是满的谁是空的), 通常是在队头空出一个位置,比如这里我们就是用rear==front+1 表示已满!

回到内核代码中,看看Linus怎么定义的:

 

#define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode))
#define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1))
跟我们推理的一样,为空则头和尾相等,为满则rear=front+1,也就是(PIPE_SIZE(inode)==(PAGE_SIZE-1)