1.头文件
#ifndef CJ_QUEUE_H
#define CJ_QUEUE_H
#include <stdbool.h>
typedef struct _CJQUEUE_HandleTypeDef
{
unsigned int head; //队列头指针
unsigned int tail; //队列尾指针
unsigned int size; //队列缓存长度(初始化时赋值)
unsigned char *buffer; //队列缓存数组(初始化时赋值)
}CJQUEUE_HandleTypeDef;
bool cj_queue_init(CJQUEUE_HandleTypeDef *queue, void *buf, int size);
int cj_queue_read(CJQUEUE_HandleTypeDef *queue, void *buf, int len);
int cj_queue_write(CJQUEUE_HandleTypeDef *queue, const void *buf, int len);
int cj_get_queue_bufRemainLen(CJQUEUE_HandleTypeDef *queue);
void cj_clear_queue(CJQUEUE_HandleTypeDef *queue);
#endif
2.实现
#include "cjqueue.h"
#include <string.h>
#include <stdio.h>
bool cj_queue_init(CJQUEUE_HandleTypeDef *queue, void *buf, int size)
{
if (size <= 0)
{
return false;
}
queue->head = 0;
queue->tail = 0;
queue->size = size;
queue->buffer = buf;
return true;
}
int cj_queue_read(CJQUEUE_HandleTypeDef *queue, void *buf, int len)
{
char *p = buf;
int head = queue->head;
int tail = queue->tail;
int size = queue->size;
unsigned char *data = queue->buffer;
int i = 0;
while (i < len && tail != head) // 按字节读取数据
{
*p++ = data[tail++];
i++;
tail %= size; // 通过取模方式避免了if分支
}
queue->tail = tail; // 更新queue->tail的值
return i; // 返回实际读取的字节数
}
int cj_queue_write(CJQUEUE_HandleTypeDef *queue, const void *buf, int len)
{
int int_len = len;
int allow_len = 0;
int head = queue->head;
int tail = queue->tail;
int size = queue->size;
unsigned char *data = queue->buffer;
char *p = (char *)buf;
int written_len = 0; // 记录成功写入的长度
while (len > 0)
{
allow_len = (tail - head + size) % size;
if(allow_len == 0)
allow_len = size;
if(len > allow_len)
int_len = allow_len;
else
int_len = len;
if((head + int_len) > size)
int_len = (size - head);
memcpy(data + head, p, int_len);
p += int_len;
head = (head + int_len) % size;
written_len += int_len;
len -= int_len;
printf("written_len = %d, head = %d, tail = %d\n", written_len, head, tail);
/* 超出队列极限 - 队列有效数据也全部清除 */
if(tail == head)
{
printf("over flow !!!!!!!!!!!!!!\n");
break;
}
}
queue->head = head;
return written_len; // 最后返回成功写入的长度
}
/* 队列中有效数据的长度 */
int cj_get_queue_bufRemainLen(CJQUEUE_HandleTypeDef *queue)
{
int head = queue->head;
int tail = queue->tail;
int size = queue->size;
return (head - tail + size) % size;
}
void cj_clear_queue(CJQUEUE_HandleTypeDef *queue)
{
queue->head = 0;
queue->tail = 0;
}
3.注意事项
1.在多线程的队列读写,应在读写时加锁来保护。
2.环形队列读的速度慢于写时,一旦写的地址到达了读的地址时,队列将被清空。