码迷,mamicode.com
首页 > 其他好文 > 详细

为什么kfifo是环形缓冲区?

时间:2018-11-28 18:53:02      阅读:257      评论:0      收藏:0      [点我收藏+]

标签:driver   log   9.png   pre   page   pdf   异常情况   技术分享   位置   

stackoverflow 上的这个问题参阅:https://stackoverflow.com/questions/53476760/why-kfifo-is-circular-queue-in-some-blogs/

https://zh.wikipedia.org/wiki/環形緩衝區 中, 提到linux kfifo属于环形缓冲区。且在  Linux Device Drivers chapter 5     page 124 也提到了kfifo 属于环形缓冲区,那么为什么kfifo是环形缓冲区呢?

首先我们看下kfifo的结构体linux-4.16.12\include\linux  :

struct __kfifo {

    unsigned int   in;

    unsigned int   out;

    unsigned int   mask;

    unsigned int   esize;

    void     *data;

}; 

 in :代表入队列的index

 out: 代表出队列的index  

mask: 代表index掩码

esize: 代表kfifo管理的element size

data:  代表数据

其中 mask 非常关键, 首先我们观察kfifo的初始化:

 技术分享图片

其中:

.mask = __is_kfifo_ptr(&(fifo))  ?  0  :  ARRAY_SIZE((fifo).buf) – 1

0 肯定是异常情况, 则 .mask = ARRAY_SIZE((fifo).buf) – 1

在注释中有提到,

 技术分享图片

表示 size 为2的次方, 例如21= 0B10, 22=0B100, 23=0B1000 等, 则对应的mask 为0B1, 0B11, 0B111等。

 

接下来我们观察在in和out的时候mask的使用:

技术分享图片

判断条件先不管,直接来到上图中的435行。可以看到mask的用法:__kfifo->in & __tmp->kfifo.mask,然后将得到的值作为当前值的index.

接下来是get的时候:

技术分享图片

在上图中的473行, 用法与put一模一样, 并且我们知道,一个数与1相&数不变。那么我们的in和out这样做有什么意义呢?

其实这就是环形缓冲区的精髓。在初始化中我们可以看到,我们并没有将起始指针指向末尾指针,那么问题就回到了我们的标题,为什么说kfifo属于环形缓冲区?

      请看下面这张图( Linux Device Drivers chapter 5, page124):

技术分享图片

 假设我们的fifo size定义的为16,且我们put了10个节点,get了5个节点,则图应该如下所示:

技术分享图片

此时in  = 10 & 0B1111 = 10, out = 5 &  0B1111 = 5.

那么在这个基础上, 我们继续put10个节点会发生什么情况?

in = (10 +10)& 0B1111 = 0B0100, 此时 in 在什么位置?

技术分享图片

经过mask的”处理”, in 又回到了队列的开头。

      可以看到,仅仅一个mask,就就将一个线性的队列转换成了环形队列。实在是不可思议,却又如此简洁,清晰。

为什么kfifo是环形缓冲区?

标签:driver   log   9.png   pre   page   pdf   异常情况   技术分享   位置   

原文地址:https://www.cnblogs.com/syyxy/p/10033511.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!