队列在软件开发中被经常使用,该结构按照先进先出(FIFO)的原则处理数据元素。而本文介绍的环形队列是一种特殊的队列结构,它也是FIFO结构,但它是环形的,它把队列数据最后一个元素和第一个元素相连,形成一个环形,如下图所示:
先给出几种环形队列的情况:
1)FIFO空
2)存放一些数据后
3)读取一些数据
4)存储数据长度达到缓存最大值时
实现源码:
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
//判断x是否是2的次方
#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
//取a和b中最小值
#define min(a, b) (((a) < (b)) ? (a) : (b))
typedef struct {
int id;
char name[64];
int age;
}Student;
//环形队列结构
typedef struct
{
void *buffer; //缓冲区
uint32_t size; //大小
uint32_t in; //入口位置
uint32_t out; //出口位置
pthread_mutex_t *f_lock; //互斥锁
}Cyclic;
//初始化缓冲区
Cyclic* CyclicInit(void *buffer, uint32_t size, pthread_mutex_t *f_lock)
{
assert(buffer);
Cyclic *ring_buf = NULL;
if (!is_power_of_2(size)) {
fprintf(stderr,"size must be power of 2.\n");
return ring_buf;
}
ring_buf = (Cyclic *)malloc(sizeof(Cyclic));
if (!ring_buf) {
fprintf(stderr,"Failed to malloc memory,errno:%u,reason:%s",errno, strerror(errno));
return ring_buf;
}
memset(ring_buf, 0, sizeof(Cyclic));
ring_buf->buffer = buffer;
ring_buf->size = size;
ring_buf->in = 0;
ring_buf->out = 0;
ring_buf->f_lock = f_lock;
return ring_buf;
}
//释放缓冲区
void CyclicDestroy(Cyclic *ring_buf)
{
if (ring_buf) {
if (ring_buf->buffer) {
free(ring_buf->buffer);
ring_buf->buffer = NULL;
}
free(ring_buf);
ring_buf = NULL;
}
}
uint32_t __CyclicLen(const Cyclic *ring_buf)
{
return (ring_buf->in - ring_buf->out);
}
uint32_t __CyclicGet(Cyclic *ring_buf, void * buffer, uint32_t size)
{
assert(ring_buf || buffer);
uint32_t len = 0;
size = min(size, ring_buf->in - ring_buf->out);
/* first get the data from fifo->out until the end of the buffer */
len = min(size, ring_buf->size - (ring_buf->out & (ring_buf->size - 1)));
memcpy(buffer, ring_buf->buffer + (ring_buf->out & (ring_buf->size - 1)), len);
/* then get the rest (if any) from the beginning of the buffer */
memcpy(buffer + len, ring_buf->buffer, size - len);
ring_buf->out += size;
return size;
}
uint32_t __CyclicPut(Cyclic *ring_buf, void *buffer, uint32_t size)
{
assert(ring_buf || buffer);
uint32_t len = 0;
size = min(size, ring_buf->size - ring_buf->in + ring_buf->out);
/* first put the data starting from fifo->in to buffer end */
len = min(size, ring_buf->size - (ring_buf->in & (ring_buf->size - 1)));
memcpy(ring_buf->buffer + (ring_buf->in & (ring_buf->size - 1)), buffer, len);
/* then put the rest (if any) at the beginning of the buffer */
memcpy(ring_buf->buffer, buffer + len, size - len);
ring_buf->in += size;
return size;
}
//缓冲区的长度
uint32_t CyclicLen(const Cyclic *ring_buf)
{
uint32_t len = 0;
pthread_mutex_lock(ring_buf->f_lock);
len = __CyclicLen(ring_buf);
pthread_mutex_unlock(ring_buf->f_lock);
return len;
}
//从缓冲区中取数据
uint32_t CyclicGet(Cyclic *ring_buf, void *buffer, uint32_t size)
{
uint32_t ret;
pthread_mutex_lock(ring_buf->f_lock);
ret = __CyclicGet(ring_buf, buffer, size);
//buffer中没有数据
if (ring_buf->in == ring_buf->out)
ring_buf->in = ring_buf->out = 0;
pthread_mutex_unlock(ring_buf->f_lock);
return ret;
}
//向缓冲区中存放数据
uint32_t CyclicPut(Cyclic *ring_buf, void *buffer, uint32_t size)
{
uint32_t ret;
pthread_mutex_lock(ring_buf->f_lock);
ret = __CyclicPut(ring_buf, buffer, size);
pthread_mutex_unlock(ring_buf->f_lock);
return ret;
}
/*-----------------------------------------------------------------------------*/
#define BUFFER_SIZE 1024
void * consumer_proc(void *arg)
{
Student info;
Cyclic *ring_buf = (Cyclic *)arg;
while (1) {
sleep(2);
printf("------------------------------------------\n");
printf("get a student info from cyclic buffer.\n");
CyclicGet(ring_buf, (void *)&info, sizeof(Student));
printf("cyclic buffer length: %u\n", CyclicLen(ring_buf));
printf("------------------------------------------\n");
}
return (void *)ring_buf;
}
void * producer_proc(void *arg)
{
int i = 1;
Cyclic *ring_buf = (Cyclic *)arg;
Student info = {1,"zhangsan",20};
while (1) {
printf("******************************************\n");
printf("put a student info to cyclic buffer.\n");
info.id = ++i;
CyclicPut(ring_buf, (void *)&info, sizeof(Student));
printf("cyclic buffer length: %u\n", CyclicLen(ring_buf));
printf("******************************************\n");
sleep(1);
}
return (void *)ring_buf;
}
// 创建消费者线程
int consumer_thread(void *arg)
{
int err;
pthread_t tid;
err = pthread_create(&tid, NULL, consumer_proc, arg);
if (err != 0) {
fprintf(stderr, "pthread_create failed !\n");
exit(1);
}
return tid;
}
//创建生产者线程
int producer_thread(void *arg)
{
int err;
pthread_t tid;
err = pthread_create(&tid, NULL, producer_proc, arg);
if (err != 0) {
fprintf(stderr, "pthread_create failed !\n");
exit(1);
}
return tid;
}
int main()
{
pthread_mutex_t f_lock;
Cyclic *ring_buf = NULL;
char buffer[BUFFER_SIZE] = {0};
ring_buf = CyclicInit(buffer, BUFFER_SIZE, &f_lock);
if (NULL == ring_buf) {
fprintf(stderr, "CyclicInit failed.\n");
return -1;
}
producer_thread((void*)ring_buf);
consumer_thread((void*)ring_buf);
while (1)
sleep(1);
CyclicDestroy(ring_buf);
return 0;
}
运行结果:
xzkj@xzkj:~/temp$ ./test
******************************************
put a student info to cyclic buffer.
cyclic buffer length: 72
******************************************
******************************************
put a student info to cyclic buffer.
cyclic buffer length: 144
******************************************
------------------------------------------
get a student info from cyclic buffer.
cyclic buffer length: 72
------------------------------------------
******************************************
put a student info to cyclic buffer.
cyclic buffer length: 144
******************************************
******************************************
put a student info to cyclic buffer.
cyclic buffer length: 216
******************************************
------------------------------------------
get a student info from cyclic buffer.
cyclic buffer length: 144
------------------------------------------
******************************************
put a student info to cyclic buffer.
cyclic buffer length: 216
******************************************
更多文章欢迎关注微信公众号~