`

RingBuffer - 原理与实现

阅读更多
1. 原理

参考http://blog.chinaunix.net/uid-9407839-id-3954445.html

      环形缓冲区通常有一个读指针和一个写指针。读指针指向环形缓冲区中可读的数据,写指针指向环形缓冲区中可写的缓冲区。通过移动读指针和写指针就可以实现缓冲区的数据读取和写入。在通常情况下,环形缓冲区的读用户仅仅会影响读指针,而写用户仅仅会影响写指针。如果仅仅有一个读用户和一个写用户,那么不需要添加互斥保护机制就可以保证数据的正确性。如果有多个读写用户访问环形缓冲区,那么必须添加互斥保护机制来确保多个用户互斥访问环形缓冲区。

图1、图2和图3是一个环形缓冲区的运行示意图。图1是环形缓冲区的初始状态,可以看到读指针和写指针都指向第一个缓冲区处;图2是向环形缓冲区中添加了一个数据后的情况,可以看到写指针已经移动到数据块2的位置,而读指针没有移动;图3是环形缓冲区进行了读取和添加后的状态,可以看到环形缓冲区中已经添加了两个数据,已经读取了一个数据。

 

 

2. 代码实现(以RT-Thread源代码为例)

结构体定义

struct rt_ringbuffer
{
    rt_uint16_t read_index, write_index;
    rt_uint8_t *buffer_ptr;
    rt_uint16_t buffer_size;
};

 

初始化函数

void rt_ringbuffer_init(struct rt_ringbuffer *rb,
                        rt_uint8_t           *pool,
                        rt_uint16_t           size)
{
    RT_ASSERT(rb != RT_NULL);

    /* initialize read and write index */
    rb->read_index = rb->write_index = 0;

    /* set buffer pool and size */
    rb->buffer_ptr = pool;
    rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
}

 

写入函数

rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb,
                            const rt_uint8_t     *ptr,
                            rt_uint16_t           length)
{
    rt_uint16_t size;
    rt_uint16_t mask;
    rt_uint16_t write_position;
    
    RT_ASSERT(rb != RT_NULL);

    mask = rb->buffer_size - 1;
    /* whether has enough space */
    size = rb->buffer_size - (rb->write_index - rb->read_index);

    /* no space */
    if (size == 0)
        return 0;
    /* drop some data */
    if (size < length)
        length = size;

    write_position = (rb->write_index & mask);
    if (rb->buffer_size - write_position> length)
    {
        /* read_index - write_index = empty space */
        memcpy(&rb->buffer_ptr[write_position], ptr, length);
    }
    else
    {
        memcpy(&rb->buffer_ptr[write_position], ptr,
               rb->buffer_size - write_position);
        memcpy(&rb->buffer_ptr[0], &ptr[rb->buffer_size - write_position],
               length - (rb->buffer_size - write_position));
    }
    rb->write_index += length;

    return length;
}

  其中

mask = rb->buffer_size - 1;
read_position = rb->read_index & mask;

 是可以实现写指针绕回到缓冲区头部后归0,注意该操作需要在获得size后才能执行。size为缓冲区空余的空间,若需要写入的数据长度超出size,则截断。若数据长度大于缓冲区尾部到当前写指针的长度,则需分两次写入操作。

 

 读出函数

rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb,
                            rt_uint8_t           *ptr,
                            rt_uint16_t           length)
{
    rt_size_t size;
    rt_uint16_t mask;
    rt_uint16_t read_position;

    RT_ASSERT(rb != RT_NULL);
    /* whether has enough data  */
    mask = rb->buffer_size - 1;
    size = rb->write_index - rb->read_index;

    /* no data */
    if (size == 0)
        return 0;
    /* less data */
    if (size < length)
        length = size;

    read_position = rb->read_index & mask;
    if (rb->buffer_size - read_position >= length)
    {
        /* copy all of data */
        memcpy(ptr, &rb->buffer_ptr[read_position], length);
    }
    else
    {
        /* copy first and second */
        memcpy(ptr, &rb->buffer_ptr[read_position],
               rb->buffer_size - read_position);
        memcpy(&ptr[rb->buffer_size - read_position], &rb->buffer_ptr[0],
               length - rb->buffer_size + read_position);
    }
    rb->read_index += length;

    return length;
}

其中size为当前缓冲区中含有数据的长度,若需要读出的数据长度超出size,则截断。若数据长度大于尾部到当前读指针的长度,则需分两次读取操作。

 

 

 

分享到:
评论

相关推荐

    ringbuffer - 原创-高效率管理

    掌握RingBuffer的工作原理和使用方法,可以帮助我们优化数据处理流程,减少程序中的等待时间和内存消耗,尤其在处理大量数据流的场景下,如网络传输、音频视频编码解码、传感器数据采集等。通过阅读和理解这个原创的...

    ring buffer实现原理

    1、环形缓冲区的实现原理 环形缓冲区通常有一个读指针和一个写指针。读指针指向环形缓冲区中可读的数据,写指针指向环形缓冲区中可写的缓冲区。通过移动读指针和写指针就可以实现缓冲区的数据读取和写入。在通常情况...

    ring-buffer-design.rar_V2 _buffer_ring_buffer

    `ring-buffer-design.txt`可能是一个文档,详细解释了环形缓冲区的设计原理、实现细节以及在Linux v2.13.6中的具体用法。通过分析这份文档,我们可以更深入地理解无锁环形缓冲区在实际系统中的应用和优势。 总结...

    ringbuffer之C实现32位Debug库.rar

    环形缓冲区(Ring Buffer),又称为循环缓冲区...总之,“ringbuffer之C实现32位Debug库.rar”是一个包含C语言实现的环形缓冲区库,适用于32位系统,具备调试功能,便于开发人员在实际项目中实现高效的数据存储和传输。

    简单的RingBuffer库

    RingBuffer库是一个在嵌入式系统,特别是STM32微控制器平台上常见的数据结构实现,用于高效地处理数据缓冲。在嵌入式编程中,尤其是在实时...理解其工作原理并熟练使用RingBuffer,对于开发高效的STM32应用至关重要。

    disruptorqueue:基于干扰器 RingBuffer 的阻塞队列实现

    《基于Disruptor的RingBuffer实现的阻塞队列》 在Java并发编程领域,高效的数据传输和同步机制是至关重要的。Disruptor是一个由LMAX公司开发的高性能并发库,它提供了一种创新的解决方案——基于RingBuffer的阻塞...

    LwRB - Lightweight ring buffer

    轻量级环形缓冲器(Lightweight Ring Buffer,简称 LwRB)是解决这一问题的一种有效工具。由Tilen MAJERLE开发并维护,其版本号为v3.1.0,LwRB旨在提供一种轻量、高效且线程安全的方式来存储和读取数据。 环形缓冲...

    ringbuffer

    在"ringbuffer"的实现中,读写指针是关键概念,它们分别指示当前读取和写入的位置。 **1. 环形缓冲区的基本原理** 环形缓冲区在内存中分配一段固定大小的连续区域,它的两端相连形成一个环状。数据在缓冲区中按顺序...

    RingBuffer_环形缓冲区_

    环形缓冲区(RingBuffer)是一种高效的数据结构,它在内存中形成一个固定大小的循环空间,用于存储数据。在编程领域,特别是在并发处理、实时系统以及数据传输中,环形缓冲区扮演着重要的角色。它结合了队列和堆栈的...

    环形缓冲区(RingBuffer)源码

    环形缓冲区(RingBuffer),又称为循环缓冲区,是一种高效的数据处理机制,常用于多线程通信、数据采集系统以及内存管理等多个领域。它的设计理念是利用固定大小的内存空间,通过指针的循环移动来实现数据的存取,...

    RingBuffer:https的C99实现

    在`RingBuffer-master`这个压缩包中,可能包含了源代码文件、头文件、测试用例和构建脚本。源代码文件通常以`.c`和`.h`为扩展名,其中`.c`文件包含实现的函数和主逻辑,`.h`文件定义了函数原型和数据结构。测试用例...

    cloudwu-mread源码

    3. **Ringbuffer范例**:"云风的 BLOG Ringbuffer 范例.mht"很可能包含了Ring Buffer的具体代码示例,可能是用C++或其他编程语言实现的,帮助读者理解如何在程序中实现和使用Ring Buffer,包括如何添加、删除数据,...

    LMAX disruptor jar包+Demo+Api+src源码 disruptor-3.0.1.jar

    - 初始化Ring Buffer:根据预期的最大并发度和事件大小计算Ring Buffer大小。 - 创建Producer:选择适合的策略,如SingleProducerSequencer或MultiProducerSequencer。 - 设置Consumer:实现EventHandler接口,...

    ringbuff-develop.zip

    在C语言中实现环形缓冲区,需要理解其基本原理,并掌握如何在有限的内存空间中实现数据的高效读写。 环形缓冲区的核心思想是利用数组作为存储空间,通过两个指针(一个用于读取,一个用于写入)来追踪当前的数据...

    纯C ringbuf源码和示例

    环形缓冲区(Ring Buffer)是一种常见的数据结构,在嵌入式系统、实时操作系统以及网络通信等领域广泛应用。它是一个固定大小的缓冲区,其中的数据在读写操作时会形成一个循环,因此得名“环形”。在C语言中,实现...

    RingBuffer.rar_嵌入式/单片机/硬件编程_C/C++_

    这个“RingBuffer.rar”压缩包包含了一个名为“RingBuffer.c”的源代码文件,它很可能提供了C/C++语言实现的环形缓冲区功能。 环形缓冲的设计基于内存中的一个固定大小的数组,其主要特点是数据的读写操作可以在...

    ringbuf:Go 的线程安全环形缓冲区实现

    环形缓冲区(Ring Buffer)是一种常见的数据结构,它在多线程编程中扮演着重要角色,尤其是在实时系统和并发环境中。在Go语言中,由于其内置的并发原语如goroutine和channel,环形缓冲区能有效地实现数据的并发访问...

    c++实现的无锁环形队列

    1. c++实现的无锁环形队列,注释详细,讲解了环形队列的实现原理和操作技巧 2. 在linux服务器下,可以自己编译,运行,也可以修改参数后做测试 3. 编译的命令如下:g++ -std=c++11 -o test main.cpp ring_buffer.cpp...

    Delphi实现的环形缓冲区

    下面我们将详细探讨Delphi实现环形缓冲区的基本原理、设计思路以及可能的优化策略。 环形缓冲区的核心概念是利用数组的一块连续内存空间作为存储区域,一端表示写入位置,另一端表示读取位置。当写入位置追上或超过...

    Disruptor并发框架中文参考文档

    Disruptor作为一款高性能的并发框架,通过无锁设计、Ring Buffer、缓存行填充和内存屏障等关键技术实现了极高的并发性能。其在金融交易系统、实时数据分析等领域有着广泛的应用前景。了解Disruptor的工作原理和技术...

Global site tag (gtag.js) - Google Analytics