C语言 ringBuffer 实现

一、 ringBuffer 介绍

ringBuffer 称作环形缓冲,也有叫 circleBuffer 的。就是取内存中一块连续的区域用作环形缓冲区的数据存储区。这块连续的存储会被反复使用,向 ringBuffer 写入数据总是从写指针的位置开始,如写到实际存储区的末尾还没有写完,则将剩余的数据从存储区的头开始写;从该 ringBuffer 读出数据也是从读指针的位置开始,如读到实际存储区的末尾还没有读完,则从存储区的头开始读剩下的数据。

为了保证写入的数据不会覆盖 ringBuffer 里还没有被读出的数据,以及读出的数据不是已经读出过的旧数据,需要使用一个变量 btoRead 表示该 ringBuffer 中有效的数据。使用变量 length 表示该环形缓冲区中真实的缓冲大小。使用指针 source 指向实际的缓存地址。

使用 ringBuffer 读写数据,要确保读写数据的速率和实际缓冲区大小的匹配。如果不匹配,可能会导致溢出,比如读数据太慢,而写数据很快,实际的缓存区又太小,导致整个缓冲区都是还没有被读出的数据,此时新的数据就无法写入。正确使用 ringBuffer 可以保证数据的连续,降低读模块和写模块之间的耦合性。更多关于生产者-消费者模型的知识可以看这篇博客

二、代码

ringBuffer 的结构体

typedef struct {
    uint8_t *source;
    uint32_t br;
    uint32_t bw;
    uint32_t btoRead;
    uint32_t length;
}ringbuffer_t;

创建 ringBuffer 函数

void create_ringBuffer(ringbuffer_t *ringBuf, uint8_t *buf, uint32_t buf_len)
{
	ringBuf->br         = 0;
	ringBuf->bw         = 0;
	ringBuf->btoRead    = 0;
	ringBuf->source     = buf;
	ringBuf->length     = buf_len;
	printf("create ringBuffer->length = %d\n", ringBuf->length);
}

清空 ringBuffer 函数

void clear_ringBuffer(ringbuffer_t *ringBuf)
{
	ringBuf->br         = 0;
	ringBuf->bw         = 0;
	ringBuf->btoRead    = 0;
	
	//no need do this casue r_ptr and w_prt has change
//	memset((uint8_t *)ringBuf->source, 0, ringBuf->length); 
}

读数据函数

uint32_t write_ringBuffer(uint8_t *buffer, uint32_t size, ringbuffer_t *ringBuf)
{
	uint32_t len            = 0;
	uint32_t ringBuf_bw     = ringBuf->bw;
	uint32_t ringBuf_len    = ringBuf->length;
	uint8_t *ringBuf_source = ringBuf->source;
	
	if( (ringBuf_bw + size) <= ringBuf_len  )
	{
		memcpy(ringBuf_source + ringBuf_bw, bufff, size);
	}
	else
	{
		len = ringBuf_len - ringBuf_bw;
		memcpy(ringBuf_source + ringBuf_bw, buffer, len);
		memcpy(ringBuf_source, buffer + len, size - len);
	}

	ringBuf->bw = (ringBuf->bw + size) % ringBuf_len;
	ringBuf->btoRead += size;

	return size;
}

写数据函数

uint32_t read_ringBuffer(uint8_t *buffer, uint32_t size, ringbuffer_t *ringBuf)
{
	uint32_t len            = 0;
	uint32_t ringBuf_br     = ringBuf->br;
	uint32_t ringBuf_len    = ringBuf->length;
    uint8_t *ringBuf_source = ringBug->source;

	if( (ringBuf_br + size ) <= ringBuf_len )
	{
		memcpy(buffer, ringBuf_source + ringBuf_br, size);
	}
	else
	{
		len = ringBuf_len - ringBuf_br;
		memcpy(bufff, ringBuf_source + ringBuf_br, len);
		memcpy(buffer + len, ringBuf_source, size - len);
	}

	ringBuf->br = (ringBuf->br + size) % ringBuf_len;
	ringBuf->btoRead -= size;

	return size;
}

获取 ringBuffer 中的有效数据

uint32_t get_ringBuffer_btoRead(ringbuffer_t *ringBuf)
{
	return ringBuf->btoRead;
}

获取 ringBuffer 的长度

uint32_t get_ringBuffer_length(ringbuffer_t *ringBuf)
{
	return ringBuf->length;
}

三、使用方法

对 ringBuffer 的使用,首先需要又一块真实并且连续的数据存储区。可以使用 malloc 从堆区分配,也可以使用一个数组。

在写数据之前,需要对此时 ringBuffer 的剩余空间和要写入数据的大小进行比较。剩余空间使用长度 length 减去待读出数据量 btoRead 得到。

在读出数据之前,则需要对此时 ringBuffer 可读出的有效数据 btoRead 进行判断。

读出的数据不够,或者没有足够的空间写如数据,可以在调用读写函数之前进行判断,假如情况不满足,就不调用相应的读写函数。

  • 9
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
Ring buffer(环形缓冲区)可以通过多种编程语言实现,以下是一些常用语言的实现示例: C++: ```cpp template<typename T, int capacity> class RingBuffer { private: std::array<T, capacity> buffer_; int head_ = 0; int tail_ = 0; int size_ = 0; public: void push(const T& item) { buffer_[tail_] = item; tail_ = (tail_ + 1) % capacity; if (size_ == capacity) { head_ = (head_ + 1) % capacity; } else { size_++; } } T& front() { return buffer_[head_]; } void pop() { head_ = (head_ + 1) % capacity; size_--; } bool empty() const { return size_ == 0; } int size() const { return size_; } }; ``` Java: ```java public class RingBuffer<T> { private T[] buffer_; private int head_ = 0; private int tail_ = 0; private int size_ = 0; @SuppressWarnings("unchecked") public RingBuffer(int capacity) { buffer_ = (T[]) new Object[capacity]; } public void push(T item) { buffer_[tail_] = item; tail_ = (tail_ + 1) % buffer_.length; if (size_ == buffer_.length) { head_ = (head_ + 1) % buffer_.length; } else { size_++; } } public T front() { return buffer_[head_]; } public void pop() { head_ = (head_ + 1) % buffer_.length; size_--; } public boolean empty() { return size_ == 0; } public int size() { return size_; } } ``` Python: ```python class RingBuffer: def __init__(self, capacity): self.buffer = [None] * capacity self.head = 0 self.tail = 0 self.size = 0 def push(self, item): self.buffer[self.tail] = item self.tail = (self.tail + 1) % len(self.buffer) if self.size == len(self.buffer): self.head = (self.head + 1) % len(self.buffer) else: self.size += 1 def front(self): return self.buffer[self.head] def pop(self): self.head = (self.head + 1) % len(self.buffer) self.size -= 1 def empty(self): return self.size == 0 def size(self): return self.size ``` 以上是一些简单的环形缓冲区实现示例,不同语言的实现可能会有差异,但基本原理都是一样的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cyang812

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值