关于循环缓冲区(Ring Buffer)的概念,其实来自于Linux内核(Maybe),是为解决某些特殊情况下的竞争问题提供了一种免锁的方法。这种特殊的情况就是当生产者和消费者都只有一个,而在其它情况下使用它也是必须要加锁的。对应在Linux内核中有对它的定义:

struct kfifo {

unsigned char *buffer;

unsigned int size;

unsigned int in;

unsigned int out;

spinlock_t *lock;

};

当然关于对它有对应的操作函数,这里不再说了(不是今天的重点)。我们只要了解这种概念就好。

关于定义: 其中buffer指向存放数据的缓冲区,size是缓冲区的大小,in是写指针下标,out是读指针下标,lock是加到struct kfifo上的自旋锁(上面说不加锁不是这里的锁),防止多个进程并发访问此数据结构。当in==out时,说明缓冲区为空;当(in-out)==size时,说明缓冲区已满。

注:我们保有对应的读写指针,当第一批数据(蓝色)完成,第二批数据(红色)会根据当前的写指针位置继续我们的数据操作,当达到最大的Buffer_Size时,会重新回到Buffer的开始端。

对此我给出一个简单的模拟实现Class:

/*

* =====================================================================================

*

* Filename: ring_buffer_class.h

* Version: 1.0

* Created: 2013年11月28日 13时08分04秒

* Revision: none

* Compiler: clang

* Author: sim szm, xianszm007@gmail.com

*

* =====================================================================================

*/

#include

class ring_buffer {

public:

ring_buffer( void* buffer, unsigned int buffer_size );

void buffer_data( const void* data, unsigned int& len );

void get_Data( void* outData, unsigned int& len );

void skip_data( unsigned int& len );

inline unsigned int free_space();

inline unsigned int buffered_bytes();

private:

void flush_state();

unsigned char *read_ptr, *write_ptr;

unsigned char *end_pos;

unsigned char *buffer;

int max_read, max_write, buffer_data_;

};

ring_buffer::ring_buffer( void* buffer, unsigned int buffer_size ) {

buffer = (unsigned char*)buffer;

end_pos = buffer + buffer_size;

read_ptr = write_ptr = buffer;

max_read = buffer_size;

max_write = buffer_data_ = 0;

flush_state();

}

void ring_buffer::buffer_data( const void* data, unsigned int& len ) {

if ( len > (unsigned int)max_read )

len = (unsigned int)max_read;

memcpy( read_ptr, data, len );

read_ptr += len;

buffer_data_ += len;

flush_state();

}

void ring_buffer::get_Data( void* outData, unsigned int& len ) {

if ( len > (unsigned int)max_write )

len = (unsigned int)max_write;

memcpy( outData, write_ptr, len );

write_ptr += len;

buffer_data_ -= len;

flush_state();

}

void ring_buffer::skip_data( unsigned int& len ) {

unsigned int requestedSkip = len;

for ( int i=0; i<2; ++i ) { // 可能会覆盖,做两次

int skip = (int)len;

if ( skip > max_write )

skip = max_write;

write_ptr += skip;

buffer_data_ -= skip;

len -= skip;

flush_state();

}

len = requestedSkip - len;

}

inline unsigned int ring_buffer::free_space() {

return (unsigned int)max_read;

}

inline unsigned int ring_buffer::buffered_bytes() {

return (unsigned int)buffer_data_;

}

void ring_buffer::flush_state() {

if (write_ptr == end_pos)

write_ptr = buffer;

if (read_ptr == end_pos)

read_ptr = buffer;

if (read_ptr == write_ptr) {

if ( buffer_data_ > 0 ) {

max_read = 0;

max_write = end_pos - write_ptr;

} else {

max_read = end_pos - read_ptr;

max_write = 0;

}

} else if ( read_ptr > write_ptr ) {

max_read = end_pos - read_ptr;

max_write = read_ptr - write_ptr;

} else {

max_read = write_ptr - read_ptr;

max_write = end_pos - write_ptr;

}

}

我们更多要说的是Ring Buffer关于在我们在日志处理方面的一个应用,我们知道对于Program来说日志记录提供了故障前应用程序状态的详细信息,在一段时间的运行过程中,会将不断地产生大量的跟踪数据,以及调试信息并持续地将其写入到磁盘上的文本文件中。多亿进行有效的日志记录,需要使用大量的磁盘空间,并且在多线程环境中,所需的磁盘空间会成倍地增加。常规的日志处理来说存在一些问题,比如硬盘空间的可用性,以及在对一个文件写入数据时磁盘 I/O 的速度较慢。持续地对磁盘进行写入操作可能会极大地降低程序的性能,导致其运行速度缓慢。通常,可以通过使用日志轮换策略来解决空间问题,将日志保存在几个文件中,当这些文件大小达到某个预定义的字节数时,对它们进行截断和覆盖。

所以要克服空间问题并实现磁盘 I/O 的最小化,某些程序可以将它们的跟踪数据记录在内存中,仅当请求时才转储这些数据。这个循环的、内存中的缓冲区称为循环缓冲区。它可以将相关的数据保存在内存中,而不是每次都将其写入到磁盘上的文件中。在需要的时候(比如当用户请求将内存数据转储到文件中时、程序检测到一个错误时,或者由于非法的操作或者接收到的信号而引起程序崩溃时)可以将内存中的数据转储到磁盘。循环缓冲区日志记录由一个固定大小的内存缓冲区构成,进程使用这个内存缓冲区进行日志记录。

当然现在我们面对的大多是多线程的协同工作,对于日志记录来说,倘若采取传统的加锁机制访问我们的存储文件,这些线程将在获得和释放锁上花费了大部分的时间,所以采取循环缓冲区会是一个不错的办法。通过使得每个线程将数据写入到它自己的内存块,就可以完全避免同步问题。当收到来自用户的转储数据的请求时,每个线程获得一个锁,并将其转储到中心位置。或者分配一个很大的全局内存块,并将其划分为较小的槽位,其中每个槽位都可由一个线程用来进行日志记录。每个线程只能够读写它自己的槽位,而不是整个缓冲区。当每个线程第一次尝试写入数据时,它会尝试寻找一个空的内存槽位,并将其标记为忙碌。当线程获得了一个特定的槽位时,可以将跟踪槽位使用情况的位图中相应的位设置为1,当该线程退出时,重新将这个位设置为 0。在这里需要同时需要维护当前使用的槽位编号的全局列表,以及正在使用它的线程的线程信息。

但是这里需要注意的是当一个线程已经死亡,却没有释放相应的槽位,并在垃圾收集器释放该槽位之前,再次使用了这个线程 ID 并为其分配一个新的槽位。对于新的线程来说,检查全局列表并且重用相同的槽位(如果以前的实例使用了它的话),这是非常重要的。因为垃圾收集器线程和写入者线程可能同时尝试修改全局列表,所以同样也需要使用某种锁定机制。

————————————————

版权声明:本文为CSDN博主「Shim_ZoMoe」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/sim_szm/article/details/17011545

标签:Buffer,unsigned,write,buffer,int,read,缓冲区,Ring,ptr

来源: https://www.cnblogs.com/dreamboy2000/p/13091953.html

linux+循环buffer,说说循环缓冲区(Ring Buffer)相关推荐

  1. Linux ftrace 1.1、ring buffer

    1.简介 ringbuffer是trace框架的一个基础,所有的trace原始数据都是通过ringbuffer记录的.ringbuffer的作用主要有几个: 1.存储在内存中,速度非常快,对系统性能的 ...

  2. 网卡的 Ring Buffer 详解

    网卡的 Ring Buffer 详解 1. 网卡处理数据包流程 网卡处理网络数据流程图: 图片来自参考链接1 上图中虚线步骤的解释: DMA 将 NIC 接收的数据包逐个写入 sk_buff ,一个数 ...

  3. leetcode 622. Design Circular Queue | 622. 设计循环队列(Ring Buffer)

    题目 https://leetcode.com/problems/design-circular-queue/ 题解 Ring Buffer 的实现,rear 指向新插入的位置,front 指向最旧的 ...

  4. SQL Server 环形缓冲区(Ring Buffer) -- 介绍

    SQL Server 环形缓冲区(Ring Buffer) -- 介绍 以下关于Ring Buffer的介绍转载自: http://zh.wikipedia.org/wiki/%E7%92%B0%E5 ...

  5. linux内核中的循环缓冲区

    Linux内核中的循环缓冲区(circular buffer)为解决某些特殊情况下的竞争问题提供了一种免锁的方法.这种特殊的情况就是当生产者和消费者都只有一个,而在其它情况下使用它也是必须要加锁的. ...

  6. 优秀的内存规划方法——环形缓冲区(ring buffer)

    目录 什么是环形缓冲区 使用环形buffer的好处 环形buffer的使用场景 进程间通信 网络IO 区分缓冲区是满或者是空 计数 保持一个存储单元为空 镜像指示位 buffer满了之后的操作 实时流 ...

  7. 环形缓冲区的实现原理(ring buffer)

    消息队列锁调用太频繁的问题算是解决了,另一个让人有些苦恼的大概是这太多的内存分配和释放操作了.频繁的内存分配不但增加了系统开销,更使得内存碎片不断增多,非常不利于我们的服务器长期稳定运行.也许我们可以 ...

  8. SQL Server 环形缓冲区(Ring Buffer) -- 环形缓冲在AlwaysOn的应用

    SQL Server 环形缓冲区(Ring Buffer) -- 环形缓冲在AlwaysOn的应用 可以从SQL Server环形缓冲区得到一些诊断AlwaysOn的信息,或从sys.dm_os_ri ...

  9. Ring Buffer (circular Buffer)环形缓冲区简介

    https://blog.csdn.net/langeldep/article/details/8888582 关于环形缓冲区的知识,请看这里 http://en.wikipedia.org/wiki ...

最新文章

  1. 你认识它们吗?2014十大科技流行词
  2. zabbix使用脚本监控
  3. 无法打开登录 'ASPState' 中请求的数据库。登录失败。
  4. 访问线上平台出现http状态码“502”和“504”
  5. bigmp4.com AI 视频无损放大高清补帧工具
  6. Methods of integrating data to uncover genotype–phenotype interactions 翻译
  7. .NET c#中调用地图
  8. 寻中华文化之根 承抗战先烈之志
  9. 2021年焊工(初级)报名考试及焊工(初级)新版试题
  10. [ Vue.js ] 报错 ‘scope‘ is defined but never used vue/no-unused-vars
  11. java做小游戏扫雷(附源码)
  12. Linux进程池、线程池调研
  13. Dva.js 入门级教学文档-1
  14. 河北工业职业技术学院计算机怎样,河北工业职业技术学院宿舍怎么样 住宿条件好不好...
  15. Unity 骨骼动画
  16. 基于python-django的neo4j人民的名义关系图谱查询系统
  17. C语言丨整蛊必备小程序,好玩炸翻天(附源码)
  18. Redis使用的21条军规(规范)
  19. JavaScript 正则表达式实现表单验证
  20. 编写优雅的JavaScript——前言

热门文章

  1. 一键批量PDF转换成图片文件
  2. 【项目管理工具】—— Microsoft Office Project 介绍
  3. Java毕业设计-流浪动物救助系统
  4. VC 常见的108个问题[转]
  5. 使用H5Streamer轻松搭建视频监控项目
  6. 云脉相册管理,检索轻松便捷
  7. Facebook工程师告诉你,如何正确的阅读《算法导论》(CLRS)?
  8. 深刻揭露当今楼市中的七大谬论
  9. 活动回顾|Apache Doris 向量化技术实现与后续规划
  10. 【解决方案】Error response from daemon: Conflict. The container name /mongo is already in use by contain