__kfifo_put和__kfifo_get

本文深入解析无锁队列的设计原理,通过具体代码示例,详细解释了inout指针的工作机制,揭示了取模操作如何使in/out指针无限增长而不会造成问题。通过博主的细致解读,读者将对无锁队列的内部运作有更深刻的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

最近了解无锁队列的时候,看了这个博主的文章,感觉这个设计挺巧妙的。有些地方我不是很理解,看了好几遍才能了解,所以在代码上加上一点自己的注释。

 

原作者提的in out指针绕回原点,一开始我理解成in指针会到out的前面,读取的时候循环找。后来发现其实不是这样的,因为做了取模,in/out无限增长也没有关系。

--------------------- 
作者:海枫 
来源:优快云 
原文:https://blog.youkuaiyun.com/linyt/article/details/53355355 
版权声明:本文为博主原创文章,转载请附上博文链接!

 

 

-------------------------

unsigned int __kfifo_put(struct kfifo *fifo,
             unsigned char *buffer, unsigned int len)
{
    unsigned int l;

    len = min(len, fifo->size - fifo->in + fifo->out);
    //这一步是取buffer长度和队列剩余长度较小值。如果len小,说明可以全部放入。如果第二参数小,
    //说明只能尽量满足。
    /*
     * Ensure that we sample the fifo->out index -before- we
     * start putting bytes into the kfifo.
     */

    smp_mb();

    /* first put the data starting from fifo->in to buffer end */
    l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
    //这个l是指in右侧的空间。同上,尽量满足。
    memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
    //先填充in右侧空间。
    /* then put the rest (if any) at the beginning of the buffer */
    memcpy(fifo->buffer, buffer + l, len - l);
    //再从头开始填充。
    /*
     * Ensure that we add the bytes to the kfifo -before-
     * we update the fifo->in index.
     */

    smp_wmb();

    fifo->in += len;
    //最后再偏移in。
    return len;
}

 

unsigned int __kfifo_get(struct kfifo *fifo,
             unsigned char *buffer, unsigned int len)
{
    unsigned int l;

    len = min(len, fifo->in - fifo->out);

    /*
     * Ensure that we sample the fifo->in index -before- we
     * start removing bytes from the kfifo.
     */

    smp_rmb();

    /* first get the data from fifo->out until the end of the buffer */
    l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
    memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);

    /* then get the rest (if any) from the beginning of the buffer */
    memcpy(buffer + l, fifo->buffer, len - l);

    /*
     * Ensure that we remove the bytes from the kfifo -before-
     * we update the fifo->out index.
     */

    smp_mb();

    fifo->out += len;

    return len;
}
--------------------- 
作者:海枫 
来源:优快云 
原文:https://blog.youkuaiyun.com/linyt/article/details/53355355 
版权声明:本文为博主原创文章,转载请附上博文链接!
### 关于 `kfifo_init` 函数的使用 在Linux内核编程环境中,`kfifo_init` 是用于初始化一个FIFO(先进先出队列)结构体的关键函数之一[^1]。此函数允许开发者创建并配置一个具有特定大小类型的FIFO缓冲区。 #### 基本定义与参数说明 该函数原型如下所示: ```c int kfifo_init(struct kfifo *fifo, unsigned char *buffer, unsigned int size); ``` - **struct kfifo \*fifo**: 需要被初始化的FIFO对象指针。 - **unsigned char \*buffer**: FIFO所使用的内存区域地址;如果设置为NULL,则会自动分配指定大小的空间。 - **unsigned int size**: FIFO的最大容量,单位为字节。需要注意的是实际可用空间可能会小于这个值,因为内部实现可能占用部分额外开销。 当调用成功返回0表示操作完成;其他任何非零数值均代表错误状态码。 #### 使用实例 下面给出一段简单的代码片段来展示如何利用上述提到的方法来进行基本的操作: ```c #include <linux/kfifo.h> #include <linux/slab.h> // 定义一个静态声明的FIFO变量 static struct kfifo my_fifo; void setup_my_fifo(void){ // 动态申请足够的连续内存作为缓存池 unsigned char *buf; buf = kmalloc(FIFO_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; // 初始化FIFO if(kfifo_init(&my_fifo, buf, FIFO_SIZE)){ printk(KERN_ERR "Failed to init fifo\n"); kfree(buf); return -EFAULT; } } ``` 这段程序首先包含了必要的头文件,并定义了一个名为`my_fifo` 的全局FIFO变量。接着,在`setup_my_fifo()` 中动态地分配了一块适当大小的存储区给它,并尝试对其进行初始化处理。一旦发生失败情况则释放之前获取到资源并报告异常信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值