为什么kfifo是环形缓冲区?
Posted syyxy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么kfifo是环形缓冲区?相关的知识,希望对你有一定的参考价值。
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.12includelinux :
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是环形缓冲区?的主要内容,如果未能解决你的问题,请参考以下文章