1.环形队列的介绍与应用
环形队列一般应用在有大量数据流入流出的场景,在嵌入式应用中,我目前接触到适合场景就是串口的收发,当串口需要接收大量的数据时就可以采用环形队列缓冲区的形式接收信息。
2.环形队列实现的基本思路
利用环形队列实现,我们可以先从队列实现理解,先不考虑利用环形会碰到的情况,队列数据结构我们这里采用数组的方式实现。再加上读取指针与写入指针,而由于基本数据结构是数组,是常量地址,所以我们就直接用数字实现指针的效果,所以我们基本的数据结构就有了
typedef struct Ring_buffer {
unsigned char* buffer;
int buffer_size;
int write_p;
int read_p;
}Ring_buffer, * Ring_buffer_p;
接下来,我们先赋予读取指针与写入指针的具体实际含义,如图,用W代表写入指针指示,W指示的位置代表下一个将要写入的位置,同理,R指示的位置代表下一个将要读取的位置,有了实际意义以后,就方便我们分析可能出现的情况了,注意,以下分析情况先在是队列的情况下,并非环形队列,首先因为只有先写了才能读,所以说W>=R,当W=R时,这种情况代表写入的内容已经全部读完,此时已经不能再进行读取操作,这会导致R>W,所以说每次读取应该对R,W大小关系进行判断,避免读取到未写入区域,超过了访问区间,而写入条件则没有,因为假设的情况下是队列,不给空间大小的限制,无线往下写。
而环形队列写入与读取条件情况就是比刚才的多了一些,环形队列本质就是一段空间大小限制的数组,我们从初始化开始就是要先进行写入操作。
写入时会面临的情况,
1.W>R
这时,W可以写到什么时候为止呢?答案可以写到下一次与R相等时为止,但是W已经>=R,继续加怎么能与R相等呢?此时要相等的R其实是经过一轮循环以后的R,指向的都是R的位置,但是阶层不一样,此时R实际的大小其实=R+10。
2.W<R
我们在分析不是环形队列时曾经分析过,由于必须有数据写入才能读取,所以说W一定>=R但是和上面说的一样,这时其实也是因为W这是是在下一个阶层,W实际=W+10,而我们写入的数据是有限制的,不能超过数组范围,所以说W实际-R<10,这就是截至条件
3.W=R
这时就要考虑这是所有数据都读完了还是所有数据都写满了,我们可以利用,利用一个变量标识未读取数据数量,判断未读取数据数量与数据所有空间大小关系从而判断是那种情况,1.数据都写满了,这时我们有两种处理方法,第一不进行写入操作了,直接跳过即可,第二覆盖之前数据从头存储,这样我们直接把未读取数据数量标零即可,这样和第二种情况就一样了视为把之前的数据读完了即丢掉。2.数据都读完了,这时和 1.W>R 处理思路一样。
读取时碰到的情况
读取时碰到的情况其实和写入时一样,唯一少的可能就是覆盖操作,读者可以自行类比思考
3.环形队列代码实现
代码数据结构有所修改,结合之前分析添加了指针真实值变量让过程更好理解
typedef struct Ring_buffer {
unsigned char* buffer;
int buffer_size;
int write_p;
int read_p;
int write_p_Reaily;
int read_p_Reaily;
int data_len;
}Ring_buffer, * Ring_buffer_p;
完整读取写入初始化代码过程
#include"FIFO.h"
#define CHOOSE_IF_COVER_DATA 0
// init the ring buffer
int init_ring_buffer(Ring_buffer_p ring_buffer, int max_size)
{
if (ring_buffer == NULL || max_size == 0)
{
return -1;
}
memset(ring_buffer, 0, sizeof(*ring_buffer));
ring_buffer->buffer = (unsigned char*)malloc(max_size * sizeof(unsigned char));
if (ring_buffer->buffer == NULL)
{
printf("malloc the buffer fault\n");
return -1;
}
ring_buffer->buffer_size = max_size;
ring_buffer->write_p = 0;
ring_buffer->read_p = 0;
ring_buffer->data_len = 0;
ring_buffer->write_p_Reaily = 0;
ring_buffer->read_p_Reaily = 0;
printf("init the ring buffer succesfull!\n");
return 0;
}
void write_ring_Data(Ring_buffer_p ring_buffer, unsigned char Data)
{
memcpy(ring_buffer->buffer + (ring_buffer->write_p_Reaily % ring_buffer->buffer_size),&Data, 1);
}
//write the ring buffer
int write_ring_buffer(Ring_buffer_p ring_buffer, unsigned char* in_buf, int in_data_len)
{
if (in_data_len == 0)
{
printf("no data need to write to the ring buffer\n");
return -1;
}
int i;
if (ring_buffer->write_p > ring_buffer->read_p)
{
for (i = 0; i < min(in_data_len, ring_buffer->read_p + ring_buffer->buffer_size - ring_buffer->write_p); i++)
{
write_ring_Data(ring_buffer, *(in_buf + i));
ring_buffer->write_p_Reaily++;
ring_buffer->data_len++;
}
}
else if (ring_buffer->write_p < ring_buffer->read_p)
{
for (i = 0; i < min(in_data_len, ring_buffer->read_p - ring_buffer->write_p); i++)
{
write_ring_Data(ring_buffer, *(in_buf + i));
ring_buffer->write_p_Reaily++;
ring_buffer->data_len++;
}
}
else if (ring_buffer->write_p == ring_buffer->read_p)
{
// 不覆盖
#if CHOOSE_IF_COVER_DATA
if (ring_buffer->data_len == ring_buffer->buffer_size)
{
return 0;
}
else
{
for (i = 0; i < min(in_data_len, ring_buffer->read_p + ring_buffer->buffer_size - ring_buffer->write_p); i++)
{
write_ring_Data(ring_buffer, *(in_buf + i));
ring_buffer->write_p_Reaily++;
ring_buffer->data_len++;
}
}
#elif !CHOOSE_IF_COVER_DATA
//覆盖
if (ring_buffer->data_len == ring_buffer->buffer_size)
{
ring_buffer->data_len = 0;
for (i = 0; i < min(in_data_len, ring_buffer->read_p + ring_buffer->buffer_size - ring_buffer->write_p); i++)
{
write_ring_Data(ring_buffer, *(in_buf + i));
ring_buffer->write_p_Reaily++;
ring_buffer->data_len++;
}
}
else
{
for (i = 0; i < min(in_data_len, ring_buffer->read_p + ring_buffer->buffer_size - ring_buffer->write_p); i++)
{
write_ring_Data(ring_buffer, *(in_buf + i));
ring_buffer->write_p_Reaily++;
ring_buffer->data_len++;
}
}
#endif
}
ring_buffer->write_p = ring_buffer->write_p_Reaily % ring_buffer->buffer_size;
ring_buffer->write_p_Reaily = ring_buffer->write_p;
return 0;
}
void read_ring_Data(Ring_buffer_p ring_buffer, unsigned char *Data)
{
memcpy(Data, ring_buffer->buffer + (ring_buffer->read_p_Reaily % ring_buffer->buffer_size), 1);
}
//read the ring buffer
int read_ring_buffer(Ring_buffer_p ring_buffer, unsigned char* out_buf, int out_data_len)
{
//if (out_data_len == 0 || ring_buffer->data_len == 0)
//{
// printf("read data length is 0\n");
// return -1;
//}
int i;
if (ring_buffer->write_p > ring_buffer->read_p)
{
for (i = 0; i < min(out_data_len, ring_buffer->write_p - ring_buffer->read_p ); i++)
{
read_ring_Data(ring_buffer, out_buf + i);
ring_buffer->read_p_Reaily++;
ring_buffer->data_len--;
}
}
else if(ring_buffer->write_p < ring_buffer->read_p)
{
for (i = 0; i < min(out_data_len, ring_buffer->write_p + ring_buffer->buffer_size - ring_buffer->read_p); i++)
{
read_ring_Data(ring_buffer, out_buf + i);
ring_buffer->read_p_Reaily++;
ring_buffer->data_len--;
}
}
else if (ring_buffer->write_p == ring_buffer->read_p)
{
if (ring_buffer->data_len == ring_buffer->buffer_size)
{
for (i = 0; i < min(out_data_len, ring_buffer->write_p + ring_buffer->buffer_size - ring_buffer->read_p); i++)
{
read_ring_Data(ring_buffer, out_buf + i);
ring_buffer->read_p_Reaily++;
ring_buffer->data_len--;
}
}
else
return 0;
}
ring_buffer->read_p = ring_buffer->read_p_Reaily % ring_buffer->buffer_size;
ring_buffer->read_p_Reaily = ring_buffer->read_p;
return 0;
}
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define min(a,b) ((a < b)?(a):(b))
#define MAX_RING_BUFFER_LEN 4
typedef struct Ring_buffer {
unsigned char* buffer;
int buffer_size;
int write_p;
int read_p;
int write_p_Reaily;
int read_p_Reaily;
int data_len;
}Ring_buffer, * Ring_buffer_p;
void printf_ring_buffer(Ring_buffer_p ring_buffer);
int read_ring_buffer(Ring_buffer_p ring_buffer, unsigned char* out_buf, int out_data_len);
int write_ring_buffer(Ring_buffer_p ring_buffer, unsigned char* in_buf, int in_data_len);
int init_ring_buffer(Ring_buffer_p ring_buffer, int max_size);
主函数运行测试,仅参考
#include"FIFO.h"
int main(int argc, char* argv[])
{
int ret = 0;
Ring_buffer ring_buffer;
init_ring_buffer(&ring_buffer, MAX_RING_BUFFER_LEN);
printf(" %d\n", ring_buffer.read_p);
printf(" %d\n", ring_buffer.write_p);
unsigned char in_buf[] = { 2,5,3,8,6 };
for (int i = 0; i < sizeof(in_buf) / sizeof(in_buf[0]); ++i)
{
printf("the in_buf[%d] data is: %d\n", i, in_buf[i]);
}
ret = write_ring_buffer(&ring_buffer, in_buf, 4);
printf(" %d\n", ring_buffer.read_p);
printf(" %d\n",ring_buffer.write_p);
for (int i = 0; i < 4; ++i)
{
printf("the ring_buffer.buffer[%d] data is: %d\n", i, ring_buffer.buffer[i]);
}
unsigned char in_buf2[] = { 6,7 };
ret = write_ring_buffer(&ring_buffer, in_buf2, 2);
printf(" %d\n", ring_buffer.read_p);
printf(" %d\n", ring_buffer.write_p);
unsigned char out_buf[4];
ret = read_ring_buffer(&ring_buffer, out_buf, 4);
printf(" %d\n", ring_buffer.read_p);
printf(" %d\n", ring_buffer.write_p);
for (int i = 0; i < sizeof(out_buf) / sizeof(out_buf[0]); ++i)
{
printf("the out_buf [%d] data is %d\n", i, out_buf[i]);
}
//ret = read_ring_buffer(&ring_buffer, out_buf, 2);
//printf(" %d\n", ring_buffer.read_p);
//printf(" %d\n", ring_buffer.write_p);
//for (int i = 0; i < sizeof(out_buf) / sizeof(out_buf[0]); ++i)
//{
// printf("the out_buf [%d] data is %d\n", i, out_buf[i]);
//}
return 0;
}
本篇文章有参考环形缓冲区的使用_环形内存缓冲区-CSDN博客
但是思路可能出路比较大,读者可选择性参考,如果代码有逻辑上的漏洞,可以评论或私信