RingBuffer
说明
- RingBuffer(环形缓冲区)也叫做圆形队列(circular queue),使用场景比较广泛,例如:Linux内核中网络数据包的缓存,系统日志的存储等多处使用,以及被广泛的应用于异步通信以及嵌入式设备中,提供高效的数据缓存读写操作。
特征
- 环形缓冲区体现了Ringbuffer是缓冲区设计的一种。
- 圆形队列(circular queue)体现了其数据操作满足FIFO(先进先出)原则。
优点
- 内存循环使用,固定大小的内存区域,不需要申请和释放内存,内存重复使用。
缺点
- 需要进行两次内存拷贝,第一次从外部拷贝到Ringbuffer,第二次从Ringbuffer拷贝到外部使用,对于大块数据,性能影响明显。
原理
- 环形缓冲区通常有一个读指针和一个写指针,发生读写操作时,读写指针跟随操作进行移动,读指针指向下一次读取数据的内存地址,写指针指向下一次写数据的内存地址。
- 当读写指针发生越界时,需要将读写指针重置,以便内存成环,常见有以下两种做法:
- 单字节,读写指针根据buffer size 取模。
- 多字节,读写指针根据buffer size 判断,超过size置为0。
- 注意:环是逻辑上的描述,在实际内存空间中是线性的。
关键问题
- 当读写指针移动时,可能出现三种情况:
- 实际线性内存空间中,读指针在前,写指针在后。
- 实际线性内存空间中,读写指针指向同一个位置。
- 实际线性内存空间中,写指针在前,读指针在后。
- 第二种情况,当读写指针指向同一位置时,此时空间是满还是空?实际情况下空和满都有可能,Ringbuffer还未使用或者读操作追上写操作时,读写指针指向同一位置,此时为空,Ringbuffer写操作追上读操作时,此时为满。
解决办法
- 保持一个存储单元为空
- 写数据时,Ringbuffer空闲空间等于实际空闲空间减一,以保持至少一个存储单元为空,这样就避免了出现读指针被写指针追上的情况(即:缓冲区满的情况);读数据不做限制。
- 这种处理方法,如果读写指针指向同一位置,则缓冲区为空;如果写指针位于读指针的相邻后一个位置,则缓冲区为满。
- 使用变量计数
- 定义一个变量来保存数据长度,写操作时,变量加上已写数据长度,读操作时,变量减去已读数据长度,通过该变量即可获知空闲空间。
- 镜像逻辑地址法
- 在国产物联网操作系统RT-thread中使用了一种非常特殊的方式来表示队满还是空。
镜像逻辑地址法
- 这篇Blog可以借鉴,但是原理层面感觉没讲清楚。
- 解释:
- 镜像:在逻辑层面将初始位置的读写指针认为是处于镜像的正面,当指针发生翻转(重置为0)时认为指针进入镜像的反面,再翻转回来认为处于镜像的正面,类似于这样循环。
- 当读写指针处于同一镜像时,说明读写指针翻转次数是一样的(buffer size牵扯读写指针导致的),只会出现写指针在读指针前面和读写指针位置一样的情况,读写指针位置一致则说明:空间为空。
- 当读写指针处于不同镜像时,说明读写指针翻转次数相差一次,只会出现读指针在写指针前面和读写指针位置一样的情况,读写指针位置一致则说明:空间为满。
- RT-Thread中定义的 rt_ringbuffer 结构体,如下:
struct rt_ringbuffer
{rt_uint8_t *buffer_ptr;rt_uint16_t read_mirror : 1; //表示读指针的镜像正反rt_uint16_t read_index : 15;rt_uint16_t write_mirror : 1; //表示写指针的镜像正反rt_uint16_t write_index : 15;rt_int16_t buffer_size;
};
RingBuffer相关推荐
- .net thread操作串口_听说你不知道 RT-Thread 有个 ringbuffer
在嵌入式开发中,我们经常需要用到 FIFO 数据结构来存储数据,比如任务间的通信.串口数据收发等场合.很多小伙伴不知道 RT-Thread 为我们提供了一个 ringbuffer 数据结构,代码位于: ...
- 线程安全的无锁RingBuffer的实现
这里的线程安全,是指一个读线程和一个写线程,读写两个线程是安全的,而不是说多个读线程和多个写线程是安全的.. 在程序设计中,我们有时会遇到这样的情况,一个线程将数据写到一个buffer中,另外一个线程 ...
- ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue, RingBuffer
1. ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue ArrayBlockingQueue, LinkedBlocking ...
- disruptor RingBuffer初始化与生产者事件产生
在Disruptor中,为了防止伪共享导致的性能降低,所有元素都会在前后尽量填充64个字节以保证在cpu以64字节缓存数据的时候,在缓存行中,都只会有自己所需要的数据,不会导致缓冲行的更新影响到别的c ...
- disruptor 框架使用以及ringbuffer原理解析
Disruptor 概述 子主题 1 从功能上来看,Disruptor 是实现了"队列"的功能,而且是一个有界队列.那么它的应用场景自然就是"生产者-消费者"模 ...
- Disruptor RingBuffer 原理
Disruptor 源码 https://github.com/LMAX-Exchange/disruptor/blob/master/README.md https://github.com/LMA ...
- 聊聊ringbuffer
文章目录 计数法实现 镜像指示位实现 ringbuffer,是环形缓存区, 或叫环形队列. 不同于一般常见的队列,环形队列首尾相连,通过移动指针来控制队列中内容的读写. 这样做有什么好处呢? 最大的好 ...
- 二维数组8:设计题 RingBuffer的原理和实现
RingBuffer是笔者在微博遇到的一个面试题. RingBuffer的特征不需要记住,面试官会告诉你的,并且告诉你一些要求,然后根据这些要求来设计就行了. RingBuffer这种结构的使用场景 ...
- Disruptor源码解析三 RingBuffer解析
目录 系列索引 前言 主要内容 RingBuffer的要点 源码解析 系列索引 Disruptor源码解析一 Disruptor高性能之道 Disruptor源码解析二 Sequence相关类解析 D ...
- 知识巩固源码落实之3:缓冲区ringbuffer
1:背景介绍: 在日常业务开发中,使用缓冲区进行临时存储的业务场景也比较多,如tcp每个连接底层都维持一个发送缓冲区和接收缓冲区. 实现一个ringbuffer,做代码备用.(可以考虑如何对ringb ...
最新文章
- java缓冲流 复制文件_java使用缓冲流复制文件的方法
- 电气simulink常用模块_16种常用模块电路分析,电气工程师的必备
- android xml文件操作类,android操作xml
- html2image api,图像标签_图像识别 Image_API参考_API_华为云
- c 语言中unsigned char类型变量占用内存大小,C数据类型
- 计算机一级办公软件试题,计算机一级《MS Office》练习题(含答案)
- findbugs-dea_FindBugs和JSR-305
- phpcmsV9上传文件类型的设置
- Spark SQL 1.3.0 DataFrame介绍、使用及提供了些完整的数据写入
- rabbitmq的通配符模式(Topic Exchange)的*和#区别
- 全局bigdecimal反序列化转String返回数据
- MDUI登陆注册案例
- 使用JS和CSS实现图片的3D透视效果及动画
- 读取采购订单附件(GOS)-[BDS_GOS_CONNECTIONS_GET/SO_DOCUMENT_READ_API1]
- [AHK]调用小米笔记本电脑的音量调节功能
- Python学习之路:函数传递可变参数与不可变参数
- 计算机桌面成英文怎样变成中文版,怎样把电脑语言设置成英文
- CAD设置图层透明显示
- 微机原理与接口技术的基础知识
- 新变种Emotet恶意样本分析
热门文章
- php自动关机代码,win7定时关机命令是什么
- 2D图像像素点操作——平移,旋转,缩放 tcy
- 听完周杰伦的《Mojito》,我不禁想用分子料理做几颗
- python-库汇总
- 简述XSS攻击及其防范措施
- 【PS】如何简单的处理带晒伤皮肤的婚纱照?红斑/脱皮/减淡红色
- matlab仿真超声波测距,超声波测距仪制作-Arduino中文社区 - Powered by Discuz!
- MySQL 插入时,出现‘“Incorrect string value: ‘\\xF0\\x9F\\x98\\x85...‘ for column ‘commens‘ at row 3‘
- mongoDB快速入门
- 9款非常适合Sketchup的渲染插件以及优点介绍