`

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...

    Disruptor并发框架中文参考文档

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

    linux zero copy mmap

    #### 零拷贝mmap的背景与意义 在网络通信过程中,数据包通常需要经历多个处理阶段,例如从网络接口卡(NIC)接收数据包到用户空间中的应用程序,或者从用户空间发送数据包至网络接口卡。传统的方式会涉及到多次的...

Global site tag (gtag.js) - Google Analytics