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

实际项目中的环形缓冲区

在实际项目中,环形缓冲区的设计要比之前讲到的原型稍微复杂一些,需要一些接口函数来实现数据结构封装。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_tlwrb_sz_atomic_t用于表示缓冲区的大小,lwrb_evt_type_t是一个枚举,表示缓冲区操作的事件类型。

lwrb_t是主要的数据结构,表示一个环形缓冲区。它包含了指向缓冲区数据的指针、缓冲区的大小、读写指针以及一个事件回调函数。与之前介绍的最简化的环形缓冲区相比,这个结构中还包含了一个缓冲区大小和一个事件回调函数。事件回调函数用于在缓冲区操作时通知应用程序。

接下来是一系列的函数声明,这些函数用于操作环形缓冲区。例如,lwrb_init用于初始化一个环形缓冲区,lwrb_writelwrb_read用于向缓冲区写入数据和从缓冲区读取数据。

最后,代码检查是否在C++环境中。如果是,就结束extern "C"

事件

在应用程序中使用 LwRB 时,获取有关不同事件的通知可能会很有用,例如在向缓冲区写入或读取数据时获得通知。

该库支持在缓冲区数据发生修改时调用的事件,这意味着在每次读取或写入操作时都会触发事件。

一些用例:

  • 通知应用程序层 LwRB 操作已被执行并发送调试消息
  • 当应用程序使用操作系统时,当已写入/读取足够数量的字节到/从缓冲区时,解锁信号量
  • 在操作系统级别的消息队列中写入通知以唤醒另一个任务

注意: 每个修改 readwrite 内部指针的操作都被视为读取或写入操作。唯一的例外是 重置 事件,它将两个内部指针都设置为 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

相关文章:

实际项目中的环形缓冲区

在实际项目中&#xff0c;环形缓冲区的设计要比之前讲到的原型稍微复杂一些&#xff0c;需要一些接口函数来实现数据结构封装。GitHub上有个大帅哥写了一个轻量的环形缓冲区库&#xff0c;可以学习参考&#xff0c;也可以直接集成到自己的项目中&#xff0c;功能已经非常完善。…...

输出回文数-第11届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第23讲。 输出回文数&#…...

内存溢出会导致模块测试正常,植入系统失败

前些天&#xff0c;遇到了一个问题&#xff1a;需要在系统中添加一个小功能&#xff0c;单独测试&#xff0c;然后植入系统。 代码使用了从网上下载的函数&#xff0c;模块单独运行&#xff0c;没有问题&#xff0c;但是放在系统中运行就会出问题。 不得已的情况下&#xff0c…...

【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 自动挂载&#xff08;可选&#xff09; usb接口修复 一 执行命令 将位于…...

猫头虎博主第9期赠书活动:《YOLO目标检测》计算机AI视觉实战YOLO人工智能目标检测与跟踪图像处理深度学习图像检测书籍

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通Golang》…...

python 如何将英语单词翻译成中文

要将英语单词翻译成中文&#xff0c;可以使用 Python 的第三方库 googletrans。该库使用 Google Translate 提供的 API 来进行翻译。 首先&#xff0c;需要安装 googletrans 库。可以使用以下命令在终端或命令提示符中安装&#xff1a; pip install googletrans4.0.0-rc1然后…...

Linux_CentOS_7.9_MySQL_5.7配置数据库服务开机自启动之简易记录

前言&#xff1a; 作为运维保障&#xff0c;都无法准确预估硬件宕机的突发阶段&#xff0c;其生产数据实时在产出&#xff0c;那作为dba数据库服务的其重要性、必要性就突显而出。这里拿虚拟机试验做个配置记录&#xff0c;便于大家学习参考。 # 如出现服务器重启后登入报错无…...

js实现拖动盒子查看内容 内容拖动

一.分析实现过程 1.鼠标拖动的操作是&#xff0c;按下鼠标不松&#xff0c;拖动鼠标&#xff0c;就需要监听鼠标点击事件(onmousedown),鼠标拖动事件(onmousemove) 2.鼠标拖动事件的监听时机&#xff0c;是在按下鼠标之后监听的&#xff0c;所以鼠标拖动事件需要放在鼠标按下事…...

[C#]winform利用seetaface6实现C#人脸检测活体检测口罩检测年龄预测性别判断眼睛状态检测

【官方框架地址】 https://github.com/ViewFaceCore/ViewFaceCore 【算法介绍】 SeetaFace6是由中国科技公司自主研发的一款人脸识别技术&#xff0c;它基于深度学习算法&#xff0c;能够快速、准确地识别出人脸&#xff0c;并且支持多种应用场景&#xff0c;如门禁系统、移动…...

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 中两种加载类的方式&#xff0c;它们的主要区别在于加载类的时机和对异常的处理。 1.Class.forName Class.forName 是一个静态方法&#xff0c;用于在运行时加载类。它返回一个 Class 对象&#xff0c;但在加载类的过程中&am…...

找不到模块 “path“ 或其相对应的类型声明

src别名的配置 在开发项目的时候文件与文件关系可能很复杂&#xff0c;因此我们需要给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。 目的&#xff1a;在进行数据传输之前&#xff0c;SSH先对联级数据包通过加密技术进行加密处理&#xff0c;然后再进行数据传输&#xff0c;确保数据传输安全。 1、在安装前&#xff0c;要检查虚拟机可以上网&#xff0c;否则可能会导致安装失…...

C语言—数据类型

变量和基本数据类型 变量类型的概念 变量是在程序中可以发生变化的量&#xff0c;变量是有类型的&#xff0c;变量的类型决定了变量存储空间的大小以及如何解释存储的位模式。 1字节&#xff08;Byte&#xff09;8位&#xff08;bit&#xff09; 定义格式 存储类型 数据…...

静态网页设计——多彩贵州(HTML+CSS+JavaScript)(dw、sublime Text、webstorm、HBuilder X)

前言 声明&#xff1a;该文章只是做技术分享&#xff0c;若侵权请联系我删除。&#xff01;&#xff01; 感谢大佬的视频&#xff1a;https://www.bilibili.com/video/BV1cK411v7R2/?vd_source5f425e0074a7f92921f53ab87712357b 源码&#xff1a;https://space.bilibili.com…...

unity PDFRender Curved UI3.3

【PDF】PDFRender 链接&#xff1a;https://pan.baidu.com/s/1wSlmfiWTAHZKqEESxuMH6Q 提取码&#xff1a;csdn 【曲面ui】 Curved UI3.3 链接&#xff1a;https://pan.baidu.com/s/1uNZySJTW0-pPwi2FTE6fgA 提取码&#xff1a;csdn...

基于深度学习的停车位关键点检测系统(代码+原理)

摘要&#xff1a; DMPR-PS是一种基于深度学习的停车位检测系统&#xff0c;旨在实时监测和识别停车场中的停车位。该系统利用图像处理和分析技术&#xff0c;通过摄像头获取停车场的实时图像&#xff0c;并自动检测停车位的位置和状态。本文详细介绍了DMPR-PS系统的算法原理、…...

C#,入门教程(09)——运算符的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(08)——基本数据类型及使用的基础知识https://blog.csdn.net/beijinghorn/article/details/123906998 一、算术运算符号 算术运算符号包括&#xff1a;四则运算 加 , 减-, 乘*, 除/与取模%。 // 加法&#xff0c;运算 int va 1 …...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...