kfifo无锁队列分析
来源:互联网 发布:ubuntu虚拟机怎么联网 编辑:程序博客网 时间:2024/05/21 09:20
http://blog.csdn.net/linyt/article/details/5764312
1. kfifo概述
struct kfifo { unsigned char *buffer; /* the buffer holding the data */ unsigned int size; /* the size of the allocated buffer */ unsigned int in; /* data is added at offset (in % size) */ unsigned int out; /* data is extracted from off. (out % size) */ spinlock_t *lock; /* protects concurrent modifications */ };
buffer, 用于存放数据的缓存
size, buffer空间的大小,在初化时,将它向上扩展成2的幂
lock, 如果使用不能保证任何时间最多只有一个读线程和写线程,需要使用该lock实施同步。
in, out, 和buffer一起构成一个循环队列。 in指向buffer中队头,而且out指向buffer中的队尾,它的结构如示图如下:
2. kfifo_alloc 分配kfifo内存和初始化工作
struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock) { unsigned char *buffer; struct kfifo *ret; /* * round up to the next power of 2, since our 'let the indices * wrap' tachnique works only in this case. */ if (size & (size - 1)) { BUG_ON(size > 0x80000000); size = roundup_pow_of_two(size); } buffer = kmalloc(size, gfp_mask); if (!buffer) return ERR_PTR(-ENOMEM); ret = kfifo_init(buffer, size, gfp_mask, lock); if (IS_ERR(ret)) kfree(buffer); return ret; }
kfifo->size的值总是在调用者传进来的size参数的基础上向2的幂扩展,这是内核一贯的做法。这样的好处不言而喻--对kfifo->size取模运算可以转化为与运算,如下:
kfifo->in % kfifo->size 可以转化为 kfifo->in & (kfifo->size – 1),这里需要注意:kfifo->size需要大于kfifo->in。
3. __kfifo_put和__kfifo_get,巧妙的入队和出队操作,无锁并发
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); //min(参数长度,未使用的队列长度) /* * 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))); //队列后面空余的长度 memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l); /* 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; 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; }
__kfifo_put是入队操作,它先将数据放入buffer里面,最后才修改in参数;__kfifo_get是出队操作,它先将数据从buffer中移走,最后才修改out。
优化屏障和内存屏障
http://blog.csdn.net/xujianqun/article/details/7800813
问题:关键在于锁,比方说put正在改fifo->in的值,但是此时get在用这个值作判断,这时保证不会出错吗?
重磅:无锁编程系统讲解:
http://blog.csdn.net/linux_bug/article/category/5825885
简明代码:
http://blog.csdn.net/linux_bug/article/details/48653851
- kfifo无锁队列分析
- KFIFO无锁队列
- 并发无锁队列UnlockQueue(单生产者单消费者kfifo)
- MPSC无锁队列分析
- linux 内核 队列 kfifo
- 内核源码kfifo分析
- 内核数据结构之队列-kfifo
- 内核数据结构之队列----kfifo
- linux内核之kfifo队列
- kfifo
- kfifo
- kfifo
- 基于kfifo的内核无锁(Lock-free)驱动的实现
- zeromq源码分析笔记之无锁队列ypipe_t
- spdlog-mpmc_bounded_q.h 无锁队列源码分析
- Linux 内核的队列实现--kfifo
- Linux 内核的队列实现--kfifo
- Linux内核队列——kfifo
- cocos code ide单步调试
- Linux环境下查看CPU是否支持VT虚拟化 - VT-X或VT-D
- 什么样的人不适合当程序员呢?
- 2016-06-13,csdn博客启用,记录纪念之。
- Mybatis传多个参数(三种解决方案)
- kfifo无锁队列分析
- 邮件中的超链接无法跳转到其它页面并加载的原因
- Mybatis学习之开发环境搭建(1)
- [从头读历史] 第252节 春秋时期各诸侯国的地域分布
- URL编码问题
- FTP文件传输协议
- 《架构漫谈》笔记
- OSI参考模型
- 一wireshark抓包详细图文教程