当前位置: 首页 > news >正文

一种基于镜像指示位办法的RingBuffer实现,解决Mirror和2的幂个数限制

简介

在嵌入式开发中,经常有需要用到RingBuffer的概念,在RingBuffer中经常遇到一个Buffer满和Buffer空的判断的问题,一般的做法是留一个单位的buffer不用,这样做最省事,但是当RingBuffer单位是一个结构体时,这个浪费就不能接受了,市面上大多数解决办法是镜像指示位办法,但是具体实现上又有各种设计,但是并不是满足的开发需要,所以有本项目。

本项目地址:bobwenstudy/simple_ringbuffer: 一种基于镜像指示位办法的RingBuffer实现,解决Mirror和2的幂个数限制 (github.com),参考资料有:环形缓冲器 - 维基百科,自由的百科全书 (wikipedia.org),ring buffer,一篇文章讲透它? - 知乎 (zhihu.com)。

对比现有的实现,本项目的特点是。

类别simple_ringbufferkfifo(linux)ringbuffer (rt-thread)
需要mirror位(多进程风险)
需要个数为2的幂
支持结构体成员是(linux5.7)

mirror位

多了Mirror位就会有一个多进程操作的风险,除非Mirror位和数值同时写入。所以最好不要有Mirror位。

个数为2的幂

Linux的kfifo解决了Mirror位的问题,因为其用到了uint32_t回环的特性,需要个数为2个幂。虽然这样大大减少了算法工作量,也可以用位运算来优化取余预算的计算效率。但是使用起来多少不是很舒适,尤其设计到对结构体成员操作时,一不注意又要浪费Buffer。

支持结构体成员

其实如果RingBuffer成员的单位为1个字节的话,其实没必要在乎1个字节的损失,只是使用时需要多申请1个字节,多少看起来不是很清爽。

但是当RingBuffer的成员的单位为很大的值时,1个成员的损失才至关重要。

现有的项目考虑灵活性,RingBuffer需要支持各种字节操作,效率并不高,本项目针对结构体操作需要,专门设计了Data_RingBuffer工具来对多字节场景进行处理,操作效率更高,并提供了2种操作接口,以满足不同业务操作的需要。

镜像指示位-本项目实现

本项目不想有Mirror的操作问题,也不想有个数2的幂的限制。处理上做了一些特殊的处理,严格区分index和ptr的概念。

index的取值范围为[0~2n-1],并不像Linux取到最大值,解决了个数2的幂的限制。

write_index = ringbuf->write_index + len;
if (write_index >= (ringbuf->total_size << 1))
{write_index -= (ringbuf->total_size << 1);
}
ringbuf->write_index = write_index;

其中ptr的获取,考虑效率使用减法,不使用取余运算。

#define RINGBUFFER_INDEX_TO_PTR(_index, _total_size)                                               \((_index >= _total_size) ? (_index - _total_size) : (_index))
uint32_t wptr = RINGBUFFER_INDEX_TO_PTR(ringbuf->write_index, ringbuf->total_size);

代码结构

代码结构如下所示:

  • simple_ringbuffer:Ringbuffer实现,包含结构体操作实现simple_data_ringbuffer和缓冲池操作实现simple_data_ringbuffer
  • test_0.ctest_1.ctest_2.c:测试例程。
  • main.c:测试例程。
  • build.mkMakefile:Makefile编译环境。
  • README.md:说明文档
simple_ringbuffer├── simple_ringbuffer│   ├── simple_data_ringbuffer.c│   ├── simple_data_ringbuffer.h│   ├── simple_ringbuffer.c│   └── simple_ringbuffer.h├── build.mk├── code_format.py├── LICENSE├── main.c├── Makefile├── README.md├── test_0.c└── test_1.c

使用说明

具体如何使用直接看例程就行,非常简单,看函数名和变量名即可。

单字节操作

使用提供simple_ringbuffer.h接口操作即可。

// Define ringbuf.
SIMPLE_RINGBUFFER_DEFINE(test_ringbuf, 0x100);// Put data to ringbuf.
uint8_t data[0x10];
simple_ringbuffer_put(&test_ringbuf, data, sizeof(data));// Get data from ringbuf.
uint8_t rdata[0x10];
simple_ringbuffer_get(&test_ringbuf, rdata, sizeof(rdata));

结构体操作

使用提供simple_data_ringbuffer.h接口操作即可。提供了两种接口,按需使用。

struct test_user_data
{uint8_t data[0x10];
};// Define ringbuf.
SIMPLE_DATA_RINGBUFFER_DEFINE(test_ringbuf, 0x100, sizeof(struct test_user_data));// API1
// Put data to ringbuf.
struct test_user_data data;
simple_ringbuffer_put(&test_ringbuf, &data);// Get data to ringbuf.
struct test_user_data rdata;
simple_ringbuffer_get(&test_ringbuf, &rdata);// API2
// Enqueue data to ringbuf.
struct test_user_data *data = NULL;
uint16_t index = simple_data_ringbuffer_enqueue_get(&test_ringbuf, (void **)&data); // enqueue getsimple_data_ringbuffer_enqueue(&test_ringbuf, index); // real enqueue// Dequeue data from ringbuf.
struct test_user_data *data;
data = simple_data_ringbuffer_dequeue_peek(&test_ringbuf); // dequeue peeksimple_data_ringbuffer_dequeue(&test_ringbuf); // real dequeue

缓存池操作

ringbuffer必须先入先出,在部分不是先入先出场景下,又想用RingBuffer读写线程独立的特性,本项目提供了一个简易数据缓存池实现方案,通过只保存数据指针的方式,来实现非先入先出的数据缓冲池。

其结构体如下。simple_pool_t用于缓冲池管理,由于RingBuffer存储的是指针,所以需要通过item_size记录每个成员的实际大小。定义一个Pool时,需要指针数组_name##_fifo_storage[_num],其用于存储实际存放数据的指针,用RingBuffer管理。真实存数据的区域为_name##_data_storage[_num][MROUND(_data_size)]

typedef struct simple_pool
{simple_data_ringbuffer_t ringbuf;uint16_t item_size;
} simple_pool_t;#define SIMPLE_POOL_DEFINE(_name, _num, _data_size)                                                \static simple_pool_t _name;                                                                    \static void *_name##_fifo_storage[_num];                                                       \static uint8_t _name##_data_storage[_num][MROUND(_data_size)];

使用操作如下:

struct test_user_data
{uint8_t data[0x100];
};// Define pool.
SIMPLE_POOL_DEFINE(test_pool, 0x10, sizeof(struct test_user_data));// Init pool.
SIMPLE_POOL_INIT(test_pool, 0x10, sizeof(struct test_user_data));// Get data from pool.
struct test_user_data *data;
SIMPLE_POOL_DEQUEUE(&test_pool, data);// Put data to pool.
SIMPLE_POOL_ENQUEUE(&test_pool, data);

测试说明

环境搭建

本项目支持Windows和Linux编译,同时支持Code Space在线编译,如果不想搭建环境可以直接CodeSpace编译。

Windows编译

目前需要安装如下环境:

  • GCC环境,笔者用的msys64+mingw,用于编译生成exe,参考这个文章安装即可。Win7下msys64安装mingw工具链 - Milton - 博客园 (cnblogs.com)。

GitHub-CodeSpace编译

直接在线编译即可。

编译说明

本项目都是由makefile组织编译的,编译整个项目只需要执行make all即可。

也就是可以通过如下指令来编译工程:

make all

而后运行执行make run即可运行例程,例程中实现了上述文档说明的问题和API的基本测试。

PS D:\workspace\github\simple_ringbuffer> make run
Compiling  : "test_0.c"
Compiling  : "test_1.c"
Linking    : "output/main.exe"
Building   : "output/main.exe"
Start Build Image.
objcopy -v -O binary output/main.exe output/main.bin
copy from `output/main.exe' [pei-i386] to `output/main.bin' [binary]
objdump --source --all-headers --demangle --line-numbers --wide output/main.exe > output/main.lst
Print Sizetext    data     bss     dec     hex filename118200  265384    2644  386228   5e4b4 output/main.exe
./output/main.exe
Testing test_work .......................................................... pass
Testing test_work_insuff ................................................... pass
Testing test_work_invalid .................................................. pass
Testing test_work_full ..................................................... pass
Testing test_work_full_define .............................................. pass
Testing test_work_read_index_big_to_write_index ............................ pass
Testing test_work_read_index_big_to_write_index ............................ pass
Testing test_work_odd ...................................................... pass
Testing test_work_insuff_odd ............................................... pass
Testing test_work_invalid_odd .............................................. pass
Testing test_work_full_odd ................................................. pass
Testing test_work_read_index_big_to_write_index_odd ........................ pass
Testing test_data_work ..................................................... pass
Testing test_data_work_full ................................................ pass
Testing test_data_work_full_define ......................................... pass
Testing test_data_work_full_define_enqueue ................................. pass
Testing test_data_work_odd ................................................. pass
Testing test_data_work_full_odd ............................................ pass
Executing 'run: all' complete!

可以看到,所有涉及到测试都通过。

相关文章:

一种基于镜像指示位办法的RingBuffer实现,解决Mirror和2的幂个数限制

简介 在嵌入式开发中&#xff0c;经常有需要用到RingBuffer的概念&#xff0c;在RingBuffer中经常遇到一个Buffer满和Buffer空的判断的问题&#xff0c;一般的做法是留一个单位的buffer不用&#xff0c;这样做最省事&#xff0c;但是当RingBuffer单位是一个结构体时&#xff0…...

【Java开发指南 | 第十一篇】Java运算符

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 算术运算符关系运算符位运算符逻辑运算符赋值运算符条件运算符&#xff08;?:&#xff09;instanceof 运算符Java运算符优先级 Java运算符包括&#xff1a;算术运算符、关系运算符、位运算符、逻辑运算符、赋值…...

【IC前端虚拟项目】验证环境方案思路和文档组织

【IC前端虚拟项目】数据搬运指令处理模块前端实现虚拟项目说明-CSDN博客 对于mvu的验证环境,从功能角度就可以分析出需要搭建哪些部分,再看一下mvu的周围环境哈: 很明显验证环境必然要包括几个部分: 1.模拟idu发送指令; 2.模拟ram/ddr读写数据; 3.rm模拟mvu的行为; …...

程序设计|C语言教学——C语言基础1:C语言的引入和入门

一、程序的执行 1.定义 解释&#xff1a;借助一个程序&#xff0c;那个程序能够试图理解你的程序&#xff0c;然后按照你的要求执行。下次执行的时候还需要从零开始解释。 编译&#xff1a;借助一个程序&#xff0c;能够像翻译官一样&#xff0c;把你的程序翻译成机器语言&a…...

初学python记录:力扣928. 尽量减少恶意软件的传播 II

题目&#xff1a; 给定一个由 n 个节点组成的网络&#xff0c;用 n x n 个邻接矩阵 graph 表示。在节点网络中&#xff0c;只有当 graph[i][j] 1 时&#xff0c;节点 i 能够直接连接到另一个节点 j。 一些节点 initial 最初被恶意软件感染。只要两个节点直接连接&#xff0c…...

LlamaIndex 组件 - Storing

文章目录 一、储存概览1、概念2、使用模式3、模块 二、Vector Stores1、简单向量存储2、矢量存储选项和功能支持3、Example Notebooks 三、文件存储1、简单文档存储2、MongoDB 文档存储3、Redis 文档存储4、Firestore 文档存储 四、索引存储1、简单索引存储2、MongoDB 索引存储…...

在Linux系统中设定延迟任务

一、在系统中设定延迟任务要求如下&#xff1a; 要求&#xff1a; 在系统中建立easylee用户&#xff0c;设定其密码为easylee 延迟任务由root用户建立 要求在5小时后备份系统中的用户信息文件到/backup中 确保延迟任务是使用非交互模式建立 确保系统中只有root用户和easylee用户…...

JVM之方法区的详细解析

方法区 方法区&#xff1a;是各个线程共享的内存区域&#xff0c;用于存储已被虚拟机加载的类信息、常量、即时编译器编译后的代码等数据&#xff0c;虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分&#xff0c;但是也叫 Non-Heap&#xff08;非堆&#xff09; 设置方法…...

Go 使用ObjectID

ObjectID介绍 MongoDB中的ObjectId是一种特殊的12字节 BSON 类型数据&#xff0c;用于为主文档提供唯一的标识符&#xff0c;默认情况下作为 _id 字段的默认值出现在每一个MongoDB集合中的文档中。以下是ObjectId的具体组成&#xff1a; 1. 时间戳&#xff08;Timestamp&…...

基于SpringBoot+Vue的疾病防控系统设计与实现(源码+文档+包运行)

一.系统概述 在如今社会上&#xff0c;关于信息上面的处理&#xff0c;没有任何一个企业或者个人会忽视&#xff0c;如何让信息急速传递&#xff0c;并且归档储存查询&#xff0c;采用之前的纸张记录模式已经不符合当前使用要求了。所以&#xff0c;对疾病防控信息管理的提升&a…...

2024年阿里云4核8G配置云服务器价格低性能高!

阿里云4核8G服务器租用优惠价格700元1年&#xff0c;配置为ECS通用算力型u1实例&#xff08;ecs.u1-c1m2.xlarge&#xff09;4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选&#xff0c;CPU采用Intel(R) Xeon(R) Platinum处理器&#xff0c;阿里云优惠 aliyunfuwuqi…...

关于ContentProvider这一遍就够了

ContentProvider是什么&#xff1f; ContentProvider是Android四大组件之一&#xff0c;主要用于不同应用程序之间或者同一个应用程序的不同部分之间共享数据。它是Android系统中用于存储和检索数据的抽象层&#xff0c;允许不同的应用程序通过统一的接口访问数据&#xff0c;…...

《1w实盘and大盘基金预测 day23》

这几天预测错麻了&#xff0c;哈哈哈&#xff0c;完全和技术没关系&#xff0c;全是消息面。 昨日预测&#xff1a; 2958-2984-3010 证券继续下跌&#xff0c;昨天诱多把我诱惑进去了&#xff08;看2-3天的反弹也没了&#xff09;&#xff0c;今天直接出掉昨天买的。 整体操作…...

向量数据库与图数据库:理解它们的区别

作者&#xff1a;Elastic Platform Team 大数据管理不仅仅是尽可能存储更多的数据。它关乎能够识别有意义的见解、发现隐藏的模式&#xff0c;并做出明智的决策。这种对高级分析的追求一直是数据建模和存储解决方案创新的驱动力&#xff0c;远远超出了传统关系数据库。 这些创…...

WIN7用上最新版Chrome

1.下载WIN10最新版Chrome的离线安装包 谷歌浏览器 Chrome 最新版离线安装包下载地址 v123.0.6312.123 - 每日自动更新 | 异次元软件 文件名称&#xff1a;123.0.6312.123_chrome_installer.exe。 123.0.6312.123_chrome_installer.exe 文件右键解压缩得到 chrome.7z&#x…...

node.jd版本降级/升级

第一步.先清空本地安装的node.js版本 按健winR弹出窗口&#xff0c;键盘输入cmd,然后敲回车&#xff08;或者鼠标直接点击电脑桌面最左下角的win窗口图标弹出&#xff0c;输入cmd再点击回车键&#xff09; 进入命令控制行窗口&#xff0c;输入where node&#xff0c;查看本地…...

python+playwright 学习-88 禁止加载图片等资源

前言 对于爬虫的小伙伴来说,有时候只需抓取页面的文本,不用加载图片,可以加快操作页面速度,那么我们可以设置禁止加载图片等资源。 禁止图片加载 根据url地址的后缀,图片资源后缀一般是png,jpg,jpeg,gif等格式。 from playwright.sync_api import sync_playwrightwith…...

Linux:Redis7.2.4的简单在线部署(1)

注意&#xff1a;我写的这个文章是以最快速的办法去搭建一个redis的基础环境&#xff0c;作用是为了做实验简单的练习&#xff0c;如果你想搭建一个相对稳定的redis去使用&#xff0c;可以看我下面这个文章 Linux&#xff1a;Redis7.2.4的源码包部署&#xff08;2&#xff09;-…...

HackMyVM-Connection

目录 信息收集 arp nmap WEB web信息收集 dirsearch smbclient put shell 提权 系统信息收集 suid gdb提权 信息收集 arp ┌─[rootparrot]─[~/HackMyVM] └──╼ #arp-scan -l Interface: enp0s3, type: EN10MB, MAC: 08:00:27:16:3d:f8, IPv4: 192.168.9.115 S…...

Prometheus接入AlterManager配置邮件告警(基于K8S环境部署)

目录 一.配置Alertmanager告警发送至邮箱二.Prometheus接入AlertManager三.部署PrometheusAlterManager(放到一个Pod中)四. 测试告警 基于 此环境做实验 一.配置Alertmanager告警发送至邮箱 1.创建AlertManager ConfigMap资源清单 vim alertmanager-cm.yaml --- kind: Confi…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...