当前位置: 首页 > 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…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving

地址&#xff1a;LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂&#xff0c;正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...