转:架构设计:生产者/消费者模式[3]:环形缓冲区

环形队列缓冲区实际运用记录 本文介绍了在GD32中使用环形缓冲区解决CAN数据丢失问题的实现方法。首先分析了环形缓冲区的两个关键点:判断队满/队空状态和内存分配。通过结构体封装环形队列,包括数据存储数组、头尾指针和队列大小,并详细说明了需要使用二维指针进行内存分配的原因。文章还提供了完整的环形队列实现代码,包含初始化、入队、出队、判断状态等操作函数,以及内存分配的具体示例。最后提到针对不同数据类型和长度的需求,建议采用分块式内存管理进行改进。该环形缓冲区实现可直接应用于GD32的CAN通信场景中,有效防止数据丢失问题。 阅读详情

原文:http://blog.youkuaiyun.com/program_think/article/details/4040068


前一个帖子提及了队列缓冲区可能存在的性能问题及解决方法:环形缓冲区。今天就专门来描述一下这个话题。
  为了防止有人给咱扣上“过度设计”的大帽子,事先声明一下:只有当存储空间的分配/释放非常频繁并且确实产生了明显的影响,你才应该考虑环形缓冲区的使用。否则的话,还是老老实实用最基本、最简单的队列缓冲区吧。还有一点需要说明一下:本文所提及的“存储空间”,不仅包括内存,还可能包括诸如硬盘之类的存储介质。

  ★环形缓冲区 vs 队列缓冲区
  ◇外部接口相似
  在介绍环形缓冲区之前,咱们先来回顾一下普通的队列。普通的队列有一个写入端和一个读出端。队列为空的时候,读出端无法读取数据;当队列满(达到最大尺寸)时,写入端无法写入数据。
  对于使用者来讲,环形缓冲区和队列缓冲区是一样的。它也有一个写入端(用于push)和一个读出端(用于pop),也有缓冲区“满”和“空”的状态。所以,从队列缓冲区切换到环形缓冲区,对于使用者来说能比较平滑地过渡。
  ◇内部结构迥异
  虽然两者的对外接口差不多,但是内部结构和运作机制有很大差别。队列的内部结构此处就不多啰嗦了。重点介绍一下环形缓冲区的内部结构。
  大伙儿可以把环形缓冲区的读出端(以下简称R)和写入端(以下简称W)想象成是两个人在体育场跑道上追逐(R追W)。当R追上W的时候,就是缓冲区为空;当W追上R的时候(W比R多跑一圈),就是缓冲区满。
  为了形象起见,去找来一张图并略作修改,如下:

不见图、请翻墙


  从上图可以看出,环形缓冲区所有的push和pop操作都是在一个固定的存储空间内进行。而队列缓冲区在push的时候,可能会分配存储空间用于存储新元素;在pop时,可能会释放废弃元素的存储空间。所以环形方式相比队列方式,少掉了对于缓冲区元素所用存储空间的分配、释放。这是环形缓冲区的一个主要优势。

  ★环形缓冲区的实现
  如果你手头已经有现成的环形缓冲区可供使用,并且你对环形缓冲区的内部实现不感兴趣,可以跳过这段。
  ◇数组方式 vs 链表方式
  环形缓冲区的内部实现,即可基于数组(此处的数组,泛指连续存储空间)实现,也可基于链表实现。
  数组在物理存储上是一维的连续线性结构,可以在初始化时,把存储空间一次性分配好,这是数组方式的优点。但是要使用数组来模拟环,你必须在逻辑上把数组的头和尾相连。在顺序遍历数组时,对尾部元素(最后一个元素)要作一下特殊处理。访问尾部元素的下一个元素时,要重新回到头部元素(第0个元素)。如下图所示:

不见图、请翻墙


  使用链表的方式,正好和数组相反。链表省去了头尾相连的特殊处理。但是链表在初始化的时候比较繁琐,而且在有些场合(比如后面提到的跨进程的IPC)不太方便使用。
  ◇读写操作
  环形缓冲区要维护两个索引,分别对应写入端(W)和读取端(R)。写入(push)的时候,先确保环没满,然后把数据复制到W所对应的元素,最后W指向下一个元素;读取(pop)的时候,先确保环没空,然后返回R对应的元素,最后R指向下一个元素。
  ◇判断“空”和“满”
  上述的操作并不复杂,不过有一个小小的麻烦:空环和满环的时候,R和W都指向同一个位置!这样就无法判断到底是“空”还是“满”。大体上有两种方法可以解决该问题。
  办法1:始终保持一个元素不用
  当空环的时候,R和W重叠。当W比R跑得快,追到距离R还有一个元素间隔的时候,就认为环已经满。当环内元素占用的存储空间较大的时候,这种办法显得很土(浪费空间)。
  办法2:维护额外变量
  如果不喜欢上述办法,还可以采用额外的变量来解决。比如可以用一个整数记录当前环中已经保存的元素个数(该整数>=0)。当R和W重叠的时候,通过该变量就可以知道是“空”还是“满”。
  ◇元素的存储
  由于环形缓冲区本身就是要降低存储空间分配的开销,因此缓冲区中元素的类型要选好。尽量存储值类型的数据,而不要存储指针(引用)类型的数据。因为指针类型的数据又会引起存储空间(比如堆内存)的分配和释放,使得环形缓冲区的效果打折扣。

  ★应用场合
  刚才介绍了环形缓冲区内部的实现机制。按照前一个帖子的惯例,我们来介绍一下在线程和进程方式下的使用。
  如果你所使用的编程语言和开发库中带有现成的、成熟的环形缓冲区,强烈建议使用现成的库,不要重新制造轮子;确实找不到现成的,才考虑自己实现。如果你纯粹是业余时间练练手,那另当别论。
  ◇用于并发线程
  和线程中的队列缓冲区类似,线程中的环形缓冲区也要考虑线程安全的问题。除非你使用的环形缓冲区的库已经帮你实现了线程安全,否则你还是得自己动手搞定。线程方式下的环形缓冲区用得比较多,相关的网上资料也多,下面就大致介绍几个。
  对于C++的程序员,强烈推荐使用boost提供的circular_buffer模板,该模板最开始是在boost 1.35版本中引入的。鉴于boost在C++社区中的地位,大伙儿应该可以放心使用该模板。
  对于C程序员,可以去看看开源项目circbuf,不过该项目是GPL协议的,不太爽;而且活跃度不太高;而且只有一个开发人员。大伙儿慎用!建议只拿它当参考。
  对于C#程序员,可以参考CodeProject上的一个示例。
  ◇用于并发进程
  进程间的环形缓冲区,似乎少有现成的库可用。大伙儿只好自己动手、丰衣足食了。
  适用于进程间环形缓冲的IPC类型,常见的有共享内存和文件。在这两种方式上进行环形缓冲,通常都采用数组的方式实现。程序事先分配好一个固定长度的存储空间,然后具体的读写操作、判断“空”和“满”、元素存储等细节就可参照前面所说的来进行。
  共享内存方式的性能很好,适用于数据流量很大的场景。但是有些语言(比如Java)对于共享内存不支持。因此,该方式在多语言协同开发的系统中,会有一定的局限性。
  而文件方式在编程语言方面支持很好,几乎所有编程语言都支持操作文件。但它可能会受限于磁盘读写(Disk I/O)的性能。所以文件方式不太适合于快速数据传输;但是对于某些“数据单元”很大的场合,文件方式是值得考虑的。
  对于进程间的环形缓冲区,同样要考虑好进程间的同步、互斥等问题,限于篇幅,此处就不细说了。
  下一个帖子,咱们来聊一下双缓冲区的使用。


版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者编程随想和本文原始地址:

http://program-think.blogspot.com/2009/04/producer-consumer-pattern-3-circle.html




virtio介绍 (一)生产者/消费者模式 介绍spdk的时候有许多跟virtio相关,但是直接介绍太突兀,最近想先详细介绍下virtio相关的技术,并且会详细介绍virtio是什么(what),怎么实现(how),到为什么这样实现(why)。再结合代码介绍下virtio的实现细节,顺便也看下自己是否彻底消化了virtio,毕竟有些东西能讲清楚和理解是两回事。那virtio是什么?virtio是虚拟化技术中关于io虚拟化中有一项重要的技术;virtio是虚拟化环境的高性能I/O设备框架;virtio是一种协议,分为前端和后端; 阅读详情

相关推荐

实战:用信号量与环形缓冲区实现生产者-消费者模型

本文介绍了使用信号量(Semaphore)和环形队列实现生产者-消费者模型的方法。通过两个信号量blank_number和product_number分别控制缓冲区中的空格和产品数量,生产者等待空格后写入数据并增加产品计数,消费者等待产品后读取数据并增加空格计数。环形队列通过取模运算实现循环访问。相比条件变量方案,信号量实现更简洁高效,特别适合固定缓冲区的场景。文章提供了完整的C语言实现代码,并分析了运行结果,展示了信号量如何自动协调生产者和消费者的节奏。最后总结了信号量与条件变量的区别及各自的适用场景。

Web安全工具库 1027

详解环形队列

环形队列也是队列的一种数据结构, 也是在队头出队, 队尾入队;只是环形队列的大小是确定的, 不能进行一个长度的增加, 当你把一个环形队列创建好之后, 它能存放的元素个数是确定的;一般我们实现这个环形队列是通过一个连续的结构来实现的;虽然环形队列在逻辑上是环形的, 但在物理上是一个定长的数组;那如何在逻辑上形成一个环形的变化, 主要是在头尾指针当走到连续空间的末尾的时候, 它会做一个重置的操作。环形队列可以用于很多场景,比如计算机中的任务调度、打印机任务队列等等/*循环队列*/

D3540987120的博客 1732

CAN_FIFO_CAN总线环形fifo_STM32CAN_stm32环形fifo_canfifo满_STM32HCAN_

STM32H767IGT6 CAN 总线接收发送环形FIFO

环形队列的原理介绍及其代码实现

环形队列的这种数据结构,应用在很多框架的底层,高效简洁

qq_39329062的博客 3097

基于环形缓冲区的CAN驱动模块

基于环形缓冲区的CAN驱动模块、电子技术,开发板制作交流

VS Code ESP-IDF无法找到源文件、头文件波浪线解决

背景:想要编译小智AI项目,可以正常编译。但是一些头文件,例如#include <nvs.h>等无法找到。

Hot_Ant的博客 1489

环形队列的实现

0. 目录 文章目录0. 目录1. 起因2. 概念3. 实现3.1 结构体3.2 存取机制3.2.1 存3.2.2 取4. Kfifo5. 参考链接 1. 起因 做嵌入式的过程中,很容易用到环形队列来做一个buffer缓存的管理。个人感觉这么几种场景用的比较多。 多线程场景 比如A模块给B模块发数据,B模块通过中断实时收取,但是不能实时处理,就需要进行缓存,在另外一个线程中处理。 输入速率不稳定...

YoYo的桃子树 1088

(学习笔记)机器人自主导航从零开始第四步———Rviz、Gazebo、Meshlab的安装

一、Rviz的安装 Rviz是一个

qq_59475883的博客 5057

使用C语言实现循环队列

队列是一种特殊的线性表,只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。

Monstres的博客 1111

Cluster Computing投稿

在overleaf中新建picins.sty文件,该文件是导入的包在.tex文件中添加以下内容\usepackage{picins}%实现作者简介%下边这块有几个人复制几段\vspace{0\baselineskip} %这一行控制作者间隔,可视情况改数字!!!!!!!!

这里是萤石ym的学习路途,努力搬砖! 5533

ai数字人系统部署

这段代码实现了基本的语音交互闭环,用户通过语音输入问题,数字人识别语音后进行自然语言理解并生成回复,再将回复转换为语音输出。但实际应用中的 AI 数字人系统更为复杂,如形象渲染需专业图形引擎(如 Unity、Unreal Engine),自然语言处理也会涉及更复杂的模型微调及多轮对话管理等。一个完整的 AI 数字人系统涵盖形象生成、自然语言处理、动作控制等多个复杂功能,下面为你提供一个 Python 示例,整合多个库来实现数字人基础功能,包括语音交互、简单的自然语言理解以及通过虚拟形象展示对话。

weixin_ggwwsscc的博客 368

(转)架构设计:生产者/消费者模式[3]:环形缓冲区

前一个帖子提及了队列缓冲区可能存在的性能问题及解决方法:环形缓冲区。今天就专门来描述一下这个话题。   为了防止有人给咱扣上“过度设计”的大帽子,事先声明一下:只有当存储空间的分配/释放非常【频繁】并且确实产生了【明显】的影响,你才应该考虑环形缓冲区的使用。否则的话,还是老老实实用最基本、最简单的队列缓冲区吧。还有一点需要说明一下:本文所提及的“存储空间”,不仅包括内存,还可能包括诸如硬盘之类的存...

cyf15238622067的博客 239

Quantum Espresso实战进阶:HSE混合泛函在能带计算中的精准应用

本文深入探讨了在Quantum Espresso中应用HSE混合泛函进行高精度能带计算的实战方法。针对传统DFT方法低估半导体带隙的问题,HSE通过混合精确交换能,显著提升计算精度。文章详细讲解了从输入文件配置、参数设置(如nqx网格、exxdiv_treatment)、到自洽与非自洽计算流程,以及结果可视化与对比的全过程,并提供了关键的调优与避坑指南,助力实现从PBE到HSE的精准进阶。

weixin_28363123的博客 225

消息队列:生产者/消费者模式

1.什么是生产者消费者模式 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。 这个阻塞队列就是用来给生产者和消费者解耦的。...

qq_39575279的博客 2万+

双端之Nginx+Php结合PostgreSQL搭建Wordpress

制作的 PG4WP 分支版本,它与所有版本的 WordPress 兼容,解决了原版的一些问题。参数,确保 PostgreSQL 正在监听默认端口(通常是 5432),或者你自定义的端口。:PG4WP 插件存在缺陷和不完整的功能,可能与最新版本的 WordPress 不兼容。的插件,它允许 WordPress 使用 PostgreSQL 数据库。,如果看到 Nginx 的默认欢迎页面,说明 Nginx 已正确安装。,如果看到 Nginx 的默认欢迎页面,说明 Nginx 已正确安装。

宇宙第一小趴菜的博客 1891

基于机器学习的电视剧类型点击量数据分析研究

1. 背景介绍 1.1 流媒体平台的兴起与电视剧市场的繁荣 近年来,随着互联网技术的飞速发展,流媒体平台如Netflix、Disney+、腾讯视频等迅速崛起,成为人们观看影视内容的主要渠道。电视剧作为流媒体平台上的重要内容类型,其点击量数据蕴含着丰富的用户偏好和市场趋势信息。

AI天才研究院 1049

生产者/消费者模式的理解及实现

  ★简介   生产者消费者模式并不是GOF提出的23种设计模式之一,23种设计模式都是建立在面向对象的基础之上的,但其实面向过程的编程中也有很多高效的编程模式,生产者消费者模式便是其中之一,它是我们编程过程中最常用的一种设计模式。   在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模...

笑看风云路的博客 9万+

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

生产者消费者模型

将上述场景例比到我们实际的软件开发过程中,经常会见到这样一幕:代码的某个模块负责生产数据(供货商),而生产出来的数据却不得不交给另一模块(消费者)来对其进行处理,在这之间我们必须要有一个类似上述超市的东西来存储数据(超市),这就抽象除了我们的生产者/消费者模型。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

kalvin_y_liu的博客 6940

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

架构设计:生产者/消费者模式

[0]:概述今天打算来介绍一下“生产者/消费者模式”,这玩意儿在很多开发领域都能派上用场。由于该模式很重要,打算分几个帖子来介绍。今天这个帖子先来扫盲一把。如果你对这个模式已经比较了解,请跳过本扫盲帖,直接看下一个帖子(关于该模式的具体应用)。看到这里,可能有同学心中犯嘀咕了:在四人帮(GOF)的23种模式里面似乎没听说过这种嘛!其实GOF那经典的23种模式主要是基于OO的(从书名《Des

1351

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

生产者、消费者模式

架构设计:生产者/消费者模式[0]:概述   今天打算来介绍一下“生产者/消费者模式”,这玩意儿在很多开发领域都能派上用场。由于该模式很重要,打算分几个帖子来介绍。今天这个帖子先来扫盲一 把。如果你对这个模式已经比较了解,请跳过本帖子,直接看下一个帖子(关于如何确定数据单元)。   看到这里,可能有同学心中犯嘀咕了:在四人帮(GOF)的 23种模式里面似乎没听说过这种嘛!其实GOF那经典的23

zealot_2002的专栏 3237
上一篇: 转:MSN 协议分析
下一篇: 【转】 firefox插件开发和调试
code09
博客等级 码龄18年 31粉丝 56原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值