[数据结构-1]:环形buffer以及读写同步

目录

一、什么是环形buffer

二、环形buffer的优点与使用场合

三、环节buffer的读写同步

3.1 基本原理

3.2 代码示例


一、什么是环形buffer

环形缓冲区(Circular Buffer)也被称为环形队列(Circular Queue)或循环缓冲区,是一种数据结构,用于在固定大小的缓冲区中存储和处理数据。

环形缓冲区的特点是首尾相连,即缓冲区的最后一个元素和第一个元素相邻。当缓冲区写满时,新数据可以覆盖旧数据,实现循环利用。

环形缓冲区常见的应用场景是数据流处理,例如音频、视频、网络通信等。它具有以下优点:

  1. 内存利用率高:由于循环利用,不会浪费内存空间。
  2. 读写效率高:读写指针移动固定步长,无需频繁移动指针或进行数据搬移操作。
  3. 简单且高效:相比其他数据结构,环形缓冲区操作简单,性能高。

环形缓冲区的实现通常需要两个指针,表示读和写的位置。读指针用于提取数据,写指针用于写入数据。同时,还需要记录缓冲区的大小和当前数据元素的数量。

通过合理管理读写指针和计数信息,可以实现有效的数据读写和同步,避免数据溢出和读写冲突的问题。

二、环形buffer的优点与使用场合

环形缓冲区(Circular Buffer)具有以下优点和适用场合:

优点:

  1. 内存利用率高:环形缓冲区能够循环利用缓冲区的空间,不会浪费内存。当缓冲区写满时,新的数据可以覆盖旧的数据,避免了频繁地分配和释放内存空间的开销。
  2. 读写效率高:环形缓冲区的读写操作只涉及指针的移动,不需要进行元素的搬移或内存复制,因此读写效率较高。读写指针以固定步长移动,无需频繁更新指针位置,特别适用于实时数据的处理。
  3. 简单且高效:相比其他数据结构,环形缓冲区的实现较为简单,并且具有较高的性能。它不需要复杂的内存管理或链表操作,可以快速读写数据。

使用场合:

  1. 数据流处理:环形缓冲区常用于处理连续的数据流,例如音频、视频、传感器数据等。通过循环利用缓冲区的空间,可实现高效的数据流存储以及快速的读取和处理。
  2. 缓冲数据传输:环形缓冲区可以用于缓冲数据的传输,特别是在生产者和消费者之间的数据传输场景。通过缓冲区,可以平衡生产者和消费者的速度差异,避免数据丢失或阻塞。
  3. 数据采样和循环记录:环形缓冲区适用于需要采样和记录连续数据的应用。例如嵌入式系统中的数据采集、实时监控系统中的历史数据记录等。
  4. 实时任务调度:在实时任务调度中,环形缓冲区可用于存储任务队列。任务按照优先级或时间顺序排列,通过环形缓冲区的循环读取,可以高效地完成实时任务的调度和执行。

总之,环形缓冲区适用于需要循环读写、高效利用内存和处理连续数据的场景,可以提高数据处理的效率和性能。

三、环节buffer的读写同步

3.1 基本原理

在环形buffer中,读和写的同步通常可以通过使用信号量来实现。环形buffer的同步通常需要维护两个指针:read_indexwrite_index,分别表示当前读取到的位置和下一个写入的位置。

读取操作需要获取已经写入的数据,因此需要等待直到有数据可用。这可以通过一个信号量来实现,信号量的值初始化为0,并在写操作完成时加1。每次读取操作首先尝试获取信号量,如果信号量的值<=0,则表示没有数据可用,需要等待。当信号量的值>0时,读取操作将从环形buffer中读取数据,更新read_index指针,并将信号量的值减1。

写入操作也需要同步,因为当buffer写满后就不能再写入新的数据了。写入操作同样需要使用一个信号量,该信号量的值初始化为buffer的大小,并在读取操作完成时加1。每次写入操作首先尝试获取信号量,如果信号量的值<=0,则表示buffer已经写满,需要等待。当信号量的值>0时,写入操作将写入数据到环形buffer中,更新write_index指针,并将信号量的值减1。

这样,通过使用信号量,可以实现环形buffer的读和写的同步,避免了读写的冲突,以及buffer写满和读取空buffer的情况。

3.2 代码示例

以下是一个简单的C++代码示例,展示了如何在环形缓冲区中实现读和写的同步:

#include <iostream>
using namespace std;const int BUFFER_SIZE = 10;class CircularBuffer {
private:int buffer[BUFFER_SIZE];int readIndex;int writeIndex;int itemCount;public:CircularBuffer() {readIndex = 0;writeIndex = 0;itemCount = 0;}bool isEmpty() {return (itemCount == 0);}bool isFull() {return (itemCount == BUFFER_SIZE);}void write(int data) {if (isFull()) {cout << "Buffer is full. Cannot write data." << endl;return;}buffer[writeIndex] = data;writeIndex = (writeIndex + 1) % BUFFER_SIZE;itemCount++;cout << "Data " << data << " has been written to buffer." << endl;}int read() {if (isEmpty()) {cout << "Buffer is empty. Cannot read data." << endl;return -1; // or any other suitable error value}int data = buffer[readIndex];readIndex = (readIndex + 1) % BUFFER_SIZE;itemCount--;cout << "Data " << data << " has been read from buffer." << endl;return data;}
};int main() {CircularBuffer buffer;buffer.write(1);buffer.write(2);buffer.write(3);buffer.read();buffer.read();buffer.read();return 0;
}

在上面的示例中,CircularBuffer类表示环形缓冲区,其构造函数初始化了读写指针和计数项。isEmpty()和isFull()函数分别用于检查缓冲区是否为空和是否已满。

write(int data)函数用于将数据写入缓冲区,它先检查缓冲区是否已满,若已满则输出错误信息。若缓冲区未满,则将数据写入缓冲区,同时更新写指针和计数项。

read()函数用于从缓冲区读取数据,它先检查缓冲区是否为空,若为空则输出错误信息,并返回适当的错误值。若缓冲区非空,则读取数据到变量中,同时更新读指针和计数项。

在主函数中创建了一个CircularBuffer对象,并进行了几次写入和读取操作,以展示缓冲区的同步行为。

请注意,该示例是一个简要的示例,实际应用中可能需要更多的同步保证和错误处理机制来处理并发访问和异常情况。

3.3 环形buffer如何通过信号量实现读和写的同步, C++代码示例

要实现环形缓冲区的读和写的同步,你可以使用两个信号量来管理缓冲区的满和空状态。一个信号量用于表示缓冲区是否满,另一个信号量用于表示缓冲区是否空。下面是使用信号量实现读和写同步的C++代码示例:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;const int BUFFER_SIZE = 10;class CircularBuffer {
private:int buffer[BUFFER_SIZE];int readIndex;int writeIndex;int itemCount;mutex mtx;condition_variable bufferFull;condition_variable bufferEmpty;public:CircularBuffer() {readIndex = 0;writeIndex = 0;itemCount = 0;}bool isEmpty() {return (itemCount == 0);}bool isFull() {return (itemCount == BUFFER_SIZE);}void write(int data) {unique_lock<mutex> lock(mtx);bufferFull.wait(lock, [this] { return !isFull(); });buffer[writeIndex] = data;writeIndex = (writeIndex + 1) % BUFFER_SIZE;itemCount++;cout << "Data " << data << " has been written to buffer." << endl;lock.unlock();bufferEmpty.notify_one();}int read() {unique_lock<mutex> lock(mtx);bufferEmpty.wait(lock, [this] { return !isEmpty(); });int data = buffer[readIndex];readIndex = (readIndex + 1) % BUFFER_SIZE;itemCount--;cout << "Data " << data << " has been read from buffer." << endl;lock.unlock();bufferFull.notify_one();return data;}
};int main() {CircularBuffer buffer;thread writer([&buffer]() {for (int i = 1; i <= 5; i++) {buffer.write(i);this_thread::sleep_for(chrono::milliseconds(500));}});thread reader([&buffer]() {for (int i = 1; i <= 5; i++) {buffer.read();this_thread::sleep_for(chrono::seconds(1));}});writer.join();reader.join();return 0;
}

在上述代码中,CircularBuffer类与之前的示例代码类似。在类中添加了互斥锁(mutex)mtx和条件变量(condition variable)bufferFullbufferEmptymtx用于保护共享资源的互斥访问,bufferFullbufferEmpty用于在读写操作中进行等待和唤醒的同步。

write(int data)read()函数中,使用unique_lock来管理互斥锁。在写入操作中,调用bufferFull.wait()来等待缓冲区非满的条件满足,然后执行写入操作。在读取操作中,调用bufferEmpty.wait()来等待缓冲区非空的条件满足,然后执行读取操作。

当写入或读取操作完成后,通过调用bufferEmpty.notify_one()bufferFull.notify_one()来唤醒等待的线程。

在主函数中创建了一个writer线程和一个reader线程,并分别模拟了写入和读取操作。使用chrono库来控制线程的睡眠时间,以展示读写操作的同步行为。

需要注意的是,上述代码仅提供了一个简单的示例,实际应用中可能需要更多的同步保证和错误处理机制,以及对信号量的正确使用和释放。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/609938.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java容器技术:Docker与Kubernetes

Docker 与 Kubernetes 是目前非常流行的 Java 容器技术&#xff0c;它们可以帮助开发者更轻松地构建、部署和管理 Java 应用程序。以下是对 Docker 和 Kubernetes 的详细介绍&#xff1a; 一、Docker&#xff1a; Docker 是一种开源的容器化平台&#xff0c;可以将应用程序和其…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《考虑电氢耦合和碳交易的电氢能源系统置信间隙鲁棒规划》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 这标题涉及到一个复杂的能源系统规划问题&#xff0c;其中考虑了电氢耦合、碳交易和置信间隙鲁棒规划。以下是对标题各个部分的解读&#xff1a; 电氢耦…

矩阵中的最长递增路径

题目链接 矩阵中的最长递增路径 题目描述 注意点 不能 在 对角线 方向上移动或移动到 边界外&#xff08;即不允许环绕&#xff09; 解答思路 因为最长递增路径一定是连续的&#xff0c;所以想到使用深度优先遍历来做。如果只使用深度优先遍历会导致超时&#xff08;同一个…

MT6785安卓核心板_联发科MTK6785/Helio G95/曦力G95核心板定制

MT6785安卓核心板是基于MT6785(Helio G95)处理器&#xff0c;具备八核处理器结构&#xff0c;包括2颗主频为2.05GHz的Cortex A76处理器和6颗主频为2.0GHz的Cortex A55处理器&#xff0c;以及六颗Cortex-A55处理器。而在GPU方面&#xff0c;采用了Arm Mali-G76 MC4&#xff0c;频…

ESP32-Touch(Arduino)

Touch Touch传感器是一种外围设备&#xff0c;具有内部振荡器电路&#xff0c;可在固定时间段内测量相应GPIO引脚上的充电/放电频率。 因此&#xff0c;这些触摸传感器也被称为电容式传感器。例如&#xff0c;如果您触摸这些引脚中的任何一个&#xff0c;手指电荷将改变这个周…

MATHPILE:一个高质量的大规模的数学语料库

简介 MATHPILE&#xff1a;一个高质量、大规模的数学语料库&#xff0c;29 GB&#xff0c;包含约 95 亿个token。涵盖从 K-12 到大学、研究生水平和数学竞赛的内容&#xff0c;包括高质量教科书、讲义、科学论文等。提供详细的数据记录&#xff0c;包括数据集表格和质量注释&a…

渐变登录页

效果演示 实现了一个简单的登录页面的样式和交互效果。 Code <div class"flex"><div class"login color">Login</div><label class"color">Username :</label><input type"text" class"input&…

已安装MySQL5.7的基础上安装MySQL8教程

类似文章很多&#xff0c;但部分问题解决方案并不是很完整&#xff0c;且对细节描述不够清楚&#xff0c;特意总结一篇 在本机已经安装MySQL5.7的情况下新安装MySQL8.x的方案如下&#xff08;请按照步骤详细操作&#xff09;&#xff1a; 1.进入官网下载 https://dev.mysql.c…

【Emgu.CV教程】4.3、无缝融合应用之SeamlessClone()

SeamlessClone()函数才是真正的无缝克隆&#xff0c;它可以将一张小一点的图片&#xff0c;复制到另一张大一点的图片中&#xff0c;并且复制的位置可以用户自己定义&#xff0c;先看一下它的函数介绍&#xff1a; public static void SeamlessClone(IInputArray src, // 输入…

【乱写的】收集一些和GPU以及NCCL相关的定义(持续更新)

RDMA Remote Direct Memory Access (RDMA) 是一种超高速的网络内存访问技术&#xff0c;它允许程序以极快速度访问远程计算节点的内存。速度快的原因如下图所示&#xff0c;一次网络访问&#xff0c;不需要经过操作系统的内核&#xff08;Sockets、TCP/IP等&#xff09;&#…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -投票创建后端实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

phpcms v9后台添加草稿箱功能

一、后台添加文章模板phpcms/modules/content/templates/content_add.tpl.php中94行增加”保存草稿“按钮&#xff1a; <div class"button"><input value"<?php echo L(save_draft);?>" type"submit" name"dosubmit_draf…

读算法霸权笔记13_读后总结与感想兼导读

1. 基本信息 算法霸权&#xff1a;数学杀伤性武器的威胁 [美] 凯西奥尼尔(Cathy 著 中信出版社,2018年9月出版 1.1. 读薄率 书籍总字数220千字&#xff0c;笔记总字数32359字。 读薄率32359220000≈14.71% 1.2. 读厚方向 算法的力量&#xff1a;人类如何共同生存&#x…

vue element plus Link 链接

文字超链接 基础用法# 基础的文字链接用法。 defaultprimarysuccesswarningdangerinfo 禁用状态# 文字链接不可用状态。 defaultprimarysuccesswarningdangerinfo 下划线# 文字链接下划线。 Without UnderlineWith Underline 图标# 带图标的链接 TIP 使用 icon 属性来为…

利用Django和Bootstrap如何实现收藏功能?

要实现影片详情页中的收藏按钮&#xff0c;可以结合Bootstrap和Django来完成。以下是一种可能的实现方式&#xff1a; 数据库模型&#xff1a; 首先&#xff0c;你需要有一个数据库模型来存储用户的收藏信息。在Django中&#xff0c;可以创建一个模型来表示用户的收藏关系&…

阻塞队列(JAVA)

阻塞队列是一种特殊的队列&#xff0c;也遵守 "先进先出" 的原则。 阻塞队列能是一种线程安全的数据结构, 并且具有以下特性: 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素&#xff1b;当队列空的时候, 继续出队列也会阻塞, 直到有其他线程往…

【WinForm.NET开发】Windows窗体设计器错误页

本文内容 黄色栏此错误的实例有关此错误的帮助有关此错误的论坛帖子常见设计时错误 如果 Windows 窗体设计器由于代码、第三方组件或其他位置的错误而未能加载&#xff0c;将显示错误页而不是设计器。 此错误页不一定表示设计器中的 bug。 bug 可能位于代码隐藏文件中的某个位…

STM32F4XX的12位ADC采集数值超过4096右对齐模式设置失败

文章目录 一、前言二、问题1&#xff1a;数值超过4096三、问题1的排错过程四、问题2&#xff1a;右对齐模式设置失败五、问题2的解决方法5.1 将ADC_ExternalTrigConv设置为05.2 使用ADC_StructInit()函数 一、前言 最近在学习STM32的ADC功能&#xff0c;遇到了一个奇怪的问题。…

(一)Spring Cloud 直击微服务作用、架构应用、hystrix降级

直击微服务作用 微服务架构: 遇到了什么问题? 将单体架构拆分成微服务架构后,如果保证多个服务(项目)正常运行? 哪个技术可以解决这个问题? 微服务技术 服务治理: 服务管理,维护服务与服务之间的关系 这个技术如何使用? netflix/网…

人工智能(AI)在未来娱乐行业的革命性影响

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已逐步渗透到各行各业&#xff0c;尤其在娱乐行业中的应用前景尤为广阔。本文将深入探讨AI对未来娱乐行业可能产生的深远影响。 首先&#xff0c;内容创作领域将迎来重大变革。AI技术可以辅助甚至独立完成剧本…