实际项目中的环形缓冲区
在实际项目中,环形缓冲区的设计要比之前讲到的原型稍微复杂一些,需要一些接口函数来实现数据结构封装。GitHub上有个大帅哥写了一个轻量的环形缓冲区库,可以学习参考,也可以直接集成到自己的项目中,功能已经非常完善。
LwRB
特点
- 使用C语言编写(C11),与
size_t兼容的大小数据类型 - 独立于平台,没有特定于体系结构的代码
- 先进先出(FIFO)缓冲区实现
- 无动态内存分配,数据为静态数组
- 使用优化的内存复制而不是循环来读取/写入内存中的数据
- 在作为单个写入和单个读取条目的管道时线程安全
- 在作为单个写入和单个读取条目的管道时中断安全
- 适用于在缓冲区和应用程序内存之间进行零拷贝的DMA传输
- 支持数据的查看、读取跳过和写入前进
- 实现事件通知的支持
- 用户友好的MIT许可证
要求
- C编译器
- 少于1kB的非易失性存储器
示例代码
用于读取和写入缓冲区的简化示例代码:
/* 声明rb实例和原始数据 */
lwrb_t buff;
uint8_t buff_data[8];/* 应用程序变量 */
uint8_t data[2];
size_t len;/* 应用程序代码... */
lwrb_init(&buff, buff_data, sizeof(buff_data)); /* 初始化缓冲区 *//* 写入4个字节的数据 */
lwrb_write(&buff, "0123", 4);/* 尝试读取缓冲区 */
/* len保存读取的字节数 */
/* 当缓冲区为空时,读取直到len == 0 */
while ((len = lwrb_read(&buff, data, sizeof(data))) > 0) {printf("成功读取%d个字节\r\n", (int)len);
}
我们首先看下这个库的接口文件:
/*** \file lwrb.h* \brief LwRB - Lightweight ring buffer*//** Copyright (c) 2023 Tilen MAJERLE** Permission is hereby granted, free of charge, to any person* obtaining a copy of this software and associated documentation* files (the "Software"), to deal in the Software without restriction,* including without limitation the rights to use, copy, modify, merge,* publish, distribute, sublicense, and/or sell copies of the Software,* and to permit persons to whom the Software is furnished to do so,* subject to the following conditions:** The above copyright notice and this permission notice shall be* included in all copies or substantial portions of the Software.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR* OTHER DEALINGS IN THE SOFTWARE.** This file is part of LwRB - Lightweight ring buffer library.** Author: Tilen MAJERLE <tilen@majerle.eu>* Version: v3.1.0*/
#ifndef LWRB_HDR_H
#define LWRB_HDR_H#include <stddef.h>
#include <stdint.h>
#include <string.h>#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus *//*** \defgroup LWRB Lightweight ring buffer manager* \brief Lightweight ring buffer manager* \{*/#if !defined(LWRB_DISABLE_ATOMIC) || __DOXYGEN__
#include <stdatomic.h>/*** \brief Atomic type for size variable.* Default value is set to be `unsigned 32-bits` type*/
typedef atomic_ulong lwrb_sz_atomic_t;/*** \brief Size variable for all library operations.* Default value is set to be `unsigned 32-bits` type*/
typedef unsigned long lwrb_sz_t;
#else
typedef unsigned long lwrb_sz_atomic_t;
typedef unsigned long lwrb_sz_t;
#endif/*** \brief Event type for buffer operations*/
typedef enum {LWRB_EVT_READ, /*!< Read event */LWRB_EVT_WRITE, /*!< Write event */LWRB_EVT_RESET, /*!< Reset event */
} lwrb_evt_type_t;/*** \brief Buffer structure forward declaration*/
struct lwrb;/*** \brief Event callback function type* \param[in] buff: Buffer handle for event* \param[in] evt: Event type* \param[in] bp: Number of bytes written or read (when used), depends on event type*/
typedef void (*lwrb_evt_fn)(struct lwrb* buff, lwrb_evt_type_t evt, lwrb_sz_t bp);/* List of flags */
#define LWRB_FLAG_READ_ALL ((uint16_t)0x0001)
#define LWRB_FLAG_WRITE_ALL ((uint16_t)0x0001)/*** \brief Buffer structure*/
typedef struct lwrb {uint8_t* buff; /*!< Pointer to buffer data. Buffer is considered initialized when `buff != NULL` and `size > 0` */lwrb_sz_t size; /*!< Size of buffer data. Size of actual buffer is `1` byte less than value holds */lwrb_sz_atomic_t r; /*!< Next read pointer. Buffer is considered empty when `r == w` and full when `w == r - 1` */lwrb_sz_atomic_t w; /*!< Next write pointer. Buffer is considered empty when `r == w` and full when `w == r - 1` */lwrb_evt_fn evt_fn; /*!< Pointer to event callback function */
} lwrb_t;uint8_t lwrb_init(lwrb_t* buff, void* buffdata, lwrb_sz_t size);
uint8_t lwrb_is_ready(lwrb_t* buff);
void lwrb_free(lwrb_t* buff);
void lwrb_reset(lwrb_t* buff);
void lwrb_set_evt_fn(lwrb_t* buff, lwrb_evt_fn fn);/* Read/Write functions */
lwrb_sz_t lwrb_write(lwrb_t* buff, const void* data, lwrb_sz_t btw);
lwrb_sz_t lwrb_read(lwrb_t* buff, void* data, lwrb_sz_t btr);
lwrb_sz_t lwrb_peek(const lwrb_t* buff, lwrb_sz_t skip_count, void* data, lwrb_sz_t btp);/* Extended read/write functions */
uint8_t lwrb_write_ex(lwrb_t* buff, const void* data, lwrb_sz_t btw, lwrb_sz_t* bw, uint16_t flags);
uint8_t lwrb_read_ex(lwrb_t* buff, void* data, lwrb_sz_t btr, lwrb_sz_t* br, uint16_t flags);/* Buffer size information */
lwrb_sz_t lwrb_get_free(const lwrb_t* buff);
lwrb_sz_t lwrb_get_full(const lwrb_t* buff);/* Read data block management */
void* lwrb_get_linear_block_read_address(const lwrb_t* buff);
lwrb_sz_t lwrb_get_linear_block_read_length(const lwrb_t* buff);
lwrb_sz_t lwrb_skip(lwrb_t* buff, lwrb_sz_t len);/* Write data block management */
void* lwrb_get_linear_block_write_address(const lwrb_t* buff);
lwrb_sz_t lwrb_get_linear_block_write_length(const lwrb_t* buff);
lwrb_sz_t lwrb_advance(lwrb_t* buff, lwrb_sz_t len);/* Search in buffer */
uint8_t lwrb_find(const lwrb_t* buff, const void* bts, lwrb_sz_t len, lwrb_sz_t start_offset, lwrb_sz_t* found_idx);
lwrb_sz_t lwrb_overwrite(lwrb_t* buff, const void* data, lwrb_sz_t btw);
lwrb_sz_t lwrb_move(lwrb_t* dest, lwrb_t* src);/*** \}*/#ifdef __cplusplus
}
#endif /* __cplusplus */#endif /* LWRB_HDR_H */
首先,代码包含了一些必要的头文件,并检查是否在C++环境中。如果是,就使用extern "C"来确保C++编译器以C语言的方式处理这个库。
然后,定义了一些类型和枚举。例如,lwrb_sz_t和lwrb_sz_atomic_t用于表示缓冲区的大小,lwrb_evt_type_t是一个枚举,表示缓冲区操作的事件类型。
lwrb_t是主要的数据结构,表示一个环形缓冲区。它包含了指向缓冲区数据的指针、缓冲区的大小、读写指针以及一个事件回调函数。与之前介绍的最简化的环形缓冲区相比,这个结构中还包含了一个缓冲区大小和一个事件回调函数。事件回调函数用于在缓冲区操作时通知应用程序。
接下来是一系列的函数声明,这些函数用于操作环形缓冲区。例如,lwrb_init用于初始化一个环形缓冲区,lwrb_write和lwrb_read用于向缓冲区写入数据和从缓冲区读取数据。
最后,代码检查是否在C++环境中。如果是,就结束extern "C"。
事件
在应用程序中使用 LwRB 时,获取有关不同事件的通知可能会很有用,例如在向缓冲区写入或读取数据时获得通知。
该库支持在缓冲区数据发生修改时调用的事件,这意味着在每次读取或写入操作时都会触发事件。
一些用例:
- 通知应用程序层 LwRB 操作已被执行并发送调试消息
- 当应用程序使用操作系统时,当已写入/读取足够数量的字节到/从缓冲区时,解锁信号量
- 在操作系统级别的消息队列中写入通知以唤醒另一个任务
注意: 每个修改 read 或 write 内部指针的操作都被视为读取或写入操作。唯一的例外是 重置 事件,它将两个内部指针都设置为 0。
#include <stdio.h>
#include "lwrb/lwrb.h"// Example callback function for LwRB events
void example_event_callback(lwrb_t* buffer, lwrb_event_t event, size_t length) {switch (event) {case LWRB_EVENT_READ:printf("Read event: %zu bytes read from buffer\n", length);break;case LWRB_EVENT_WRITE:printf("Write event: %zu bytes written to buffer\n", length);break;case LWRB_EVENT_RESET:printf("Reset event: Buffer has been reset\n");break;default:break;}
}int main() {// Initialize LwRB bufferlwrb_t buffer;uint8_t data[16];lwrb_init(&buffer, data, sizeof(data));// Set the event callback functionlwrb_set_event_callback(&buffer, example_event_callback);// Example operations on the bufferlwrb_write(&buffer, (uint8_t*)"Hello", 5);lwrb_read(&buffer, data, 3);lwrb_reset(&buffer);return 0;
}
上述代码演示了如何设置 LwRB 缓冲区的事件回调函数以获取关于读取、写入和重置操作的通知。在每次读取或写入时,将调用相应的事件回调函数。
公众号 | FunIO
微信搜一搜 “funio”,发现更多精彩内容。
个人博客 | blog.boringhex.top
相关文章:
实际项目中的环形缓冲区
在实际项目中,环形缓冲区的设计要比之前讲到的原型稍微复杂一些,需要一些接口函数来实现数据结构封装。GitHub上有个大帅哥写了一个轻量的环形缓冲区库,可以学习参考,也可以直接集成到自己的项目中,功能已经非常完善。…...
输出回文数-第11届蓝桥杯选拔赛Python真题精选
[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第23讲。 输出回文数&#…...
内存溢出会导致模块测试正常,植入系统失败
前些天,遇到了一个问题:需要在系统中添加一个小功能,单独测试,然后植入系统。 代码使用了从网上下载的函数,模块单独运行,没有问题,但是放在系统中运行就会出问题。 不得已的情况下,…...
【taro react】 ---- QRCode 二维码生成
1. 需求分析 需要将输入的值转换为图片资源;由于只是单纯的展示,所以不需要很多比如加 logo 等复杂功能;不需要后端生成,直接前端操作;使用的第三方库尽可能小,功能单一;最后选择使用 qrcode-generator 库,只有 40kb。2. 使用第三方库 qrcode-generator 3. 转换 base…...
rk3566 armbian修复usb2.0并挂载U盘
文章目录 usb接口修复一 执行命令二 修改rk3566-panther-x2.dts⽂件三 查看是否识别 U盘格式化、挂载一 U盘格式化1.1 查看U盘1.2 查看U盘文件系统类型1.3 格式化为ext4系统 二 挂载U盘2.1 手动挂载2.2 自动挂载(可选) usb接口修复 一 执行命令 将位于…...
猫头虎博主第9期赠书活动:《YOLO目标检测》计算机AI视觉实战YOLO人工智能目标检测与跟踪图像处理深度学习图像检测书籍
博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通Golang》…...
python 如何将英语单词翻译成中文
要将英语单词翻译成中文,可以使用 Python 的第三方库 googletrans。该库使用 Google Translate 提供的 API 来进行翻译。 首先,需要安装 googletrans 库。可以使用以下命令在终端或命令提示符中安装: pip install googletrans4.0.0-rc1然后…...
Linux_CentOS_7.9_MySQL_5.7配置数据库服务开机自启动之简易记录
前言: 作为运维保障,都无法准确预估硬件宕机的突发阶段,其生产数据实时在产出,那作为dba数据库服务的其重要性、必要性就突显而出。这里拿虚拟机试验做个配置记录,便于大家学习参考。 # 如出现服务器重启后登入报错无…...
js实现拖动盒子查看内容 内容拖动
一.分析实现过程 1.鼠标拖动的操作是,按下鼠标不松,拖动鼠标,就需要监听鼠标点击事件(onmousedown),鼠标拖动事件(onmousemove) 2.鼠标拖动事件的监听时机,是在按下鼠标之后监听的,所以鼠标拖动事件需要放在鼠标按下事…...
[C#]winform利用seetaface6实现C#人脸检测活体检测口罩检测年龄预测性别判断眼睛状态检测
【官方框架地址】 https://github.com/ViewFaceCore/ViewFaceCore 【算法介绍】 SeetaFace6是由中国科技公司自主研发的一款人脸识别技术,它基于深度学习算法,能够快速、准确地识别出人脸,并且支持多种应用场景,如门禁系统、移动…...
c++ execl 执行 重定向
#include <unistd.h>int main() {pid_t childPid fork(); // 创建子进程if (childPid 0) {// 子进程// 关闭标准输入、输出和错误流close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);// 打开要写入的文件int fd open("output.txt", O_WRONLY…...
uni-app中实现元素拖动
uni-app中实现元素拖动 1、代码示例 <template><movable-area class"music-layout"><movable-view class"img-layout" :x"x" :y"y" direction"all"><img :src"musicDetail.bgUrl" :class&…...
Java系列-Class.forName和ClassLoader.loadClass的区别
Class.forName 和 ClassLoader.loadClass 是 Java 中两种加载类的方式,它们的主要区别在于加载类的时机和对异常的处理。 1.Class.forName Class.forName 是一个静态方法,用于在运行时加载类。它返回一个 Class 对象,但在加载类的过程中&am…...
找不到模块 “path“ 或其相对应的类型声明
src别名的配置 在开发项目的时候文件与文件关系可能很复杂,因此我们需要给src文件夹配置一个别名 // vite.config.ts import {defineConfig} from vite import vue from vitejs/plugin-vue import path from path export default defineConfig({plugins: [vue()],r…...
Linux第17步_安装SSH服务
secure shell protocol简称SSH。 目的:在进行数据传输之前,SSH先对联级数据包通过加密技术进行加密处理,然后再进行数据传输,确保数据传输安全。 1、在安装前,要检查虚拟机可以上网,否则可能会导致安装失…...
C语言—数据类型
变量和基本数据类型 变量类型的概念 变量是在程序中可以发生变化的量,变量是有类型的,变量的类型决定了变量存储空间的大小以及如何解释存储的位模式。 1字节(Byte)8位(bit) 定义格式 存储类型 数据…...
静态网页设计——多彩贵州(HTML+CSS+JavaScript)(dw、sublime Text、webstorm、HBuilder X)
前言 声明:该文章只是做技术分享,若侵权请联系我删除。!! 感谢大佬的视频:https://www.bilibili.com/video/BV1cK411v7R2/?vd_source5f425e0074a7f92921f53ab87712357b 源码:https://space.bilibili.com…...
unity PDFRender Curved UI3.3
【PDF】PDFRender 链接:https://pan.baidu.com/s/1wSlmfiWTAHZKqEESxuMH6Q 提取码:csdn 【曲面ui】 Curved UI3.3 链接:https://pan.baidu.com/s/1uNZySJTW0-pPwi2FTE6fgA 提取码:csdn...
基于深度学习的停车位关键点检测系统(代码+原理)
摘要: DMPR-PS是一种基于深度学习的停车位检测系统,旨在实时监测和识别停车场中的停车位。该系统利用图像处理和分析技术,通过摄像头获取停车场的实时图像,并自动检测停车位的位置和状态。本文详细介绍了DMPR-PS系统的算法原理、…...
C#,入门教程(09)——运算符的基础知识
上一篇: C#,入门教程(08)——基本数据类型及使用的基础知识https://blog.csdn.net/beijinghorn/article/details/123906998 一、算术运算符号 算术运算符号包括:四则运算 加 , 减-, 乘*, 除/与取模%。 // 加法,运算 int va 1 …...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
Windows电脑能装鸿蒙吗_Windows电脑体验鸿蒙电脑操作系统教程
鸿蒙电脑版操作系统来了,很多小伙伴想体验鸿蒙电脑版操作系统,可惜,鸿蒙系统并不支持你正在使用的传统的电脑来安装。不过可以通过可以使用华为官方提供的虚拟机,来体验大家心心念念的鸿蒙系统啦!注意:虚拟…...
