在之前的博客中给出了设计循环队列的思路以及源码,这些可都是经过我长期大数据测试的验证哦。当然,现在的很多开源项目和一些封装好的类或接口也都有类似的队列实现方法,之所以我还在使用自己写的这一套方法,主要是因为灵活性较大,我可以定制出适合自己的接口。而且在其上的操作逻辑和结果我也心知肚明。
好了,之所以隔了这么久写这个第三篇文章,主要是考虑到以下因素:
<1> 队列并发操作的同步问题;(安全性)
<2> 部分情况下,希望在读取队列后进行队列回写操作。(比如进行数据分析按一帧一帧进行解析的时候,发现队列里缓存数据不足一帧,此时就需要回写,等再有数据保存到队列)
下面先提出 <1> 的解决方法,使用互斥锁和信号量,给出简单例子:
Exp1:
pthread_mutex_init(&mutex);
thread1:
...
pthread_mutex_lock(&mutex);
WriteQueue(q, wbuf, writelen);
pthread_mutex_unlock(&mutex);
...
thread2:
...
pthread_mutex_lock(&mutex);
ReadQueue(q, rbuf, &readlen);
pthread_mutex_unlock(&mutex);
...
Exp2:
sem_init(&sem);
thread1:
...
sem_wait(&sem);
WriteQueue(q, wbuf, writelen);
sem_post(&sem);
...
thread2:
...
sem_wait(&sem);
ReadQueue(q, rbuf, &readlen);
sem_post(&sem);
...
其他的方式还有很多啦,就不一一列举了,小型项目开发应该是足够了。
至于方案 <2> 的解决方法,在 queue.c 中添加一个回写函数就好啦,原理也很简单,把读指针移动到之前的位置就可以啦。需要考虑的就是回写的长度大于队列当前读指针距离队列头的位置时的处理,详细可以参见我下面的代码:
unsigned int RecoverReadQueue(Queue *q, unsigned int len)
{
unsigned int ret = 0;
unsigned int rest = q->read;
if (rest >= len)
{
q->read -= len;
}
else
{
q->read = q->size - (len - rest);
}
q->space -= len;
return ret;
}
为了防止部分读者忽略了之前文章,我还是把最新的源码贴出来以供参考:
queue.h
#ifndef _QUEUE_H
#define _QUEUE_H
#include
#include
#include
#include
/**
* Queue - queue structure
* @buf: queue buffer
* @read: position of read
* @write: position of write
* @size: buffer size
* @space: writable buffer size
*/
typedef struct {
unsigned char *buf;
unsigned int read;
unsigned int write;
unsigned int size;
unsigned int space;
bool OverFlow;
} Queue;
#define Avail(q) (q->size - q->space)
extern bool Queue_Empty(Queue *q);
extern bool Queue_Full(Queue *q);
extern unsigned int RecoverReadQueue(Queue *q, unsigned int len);
extern void Queue_Init(Queue *q, int size);
extern void Queue_Destroy(Queue *q);
extern bool AddQueue(Queue *q, unsigned char val);
extern bool DelQueue(Queue *q, unsigned char *val);
extern unsigned int WriteQueue(Queue *q, unsigned char *buf, unsigned int len);
extern unsigned int ReadQueue(Queue *q, unsigned char *buf, unsigned int len);
#endif
queue.c
/*
* Queue operation API - 1.1
*
* Copyright (C) 2016 SoldierJazz (SoldierJazz@163.com)
*
* This program is free software; you can redistribute it and/or
* modify it.
*
*/
#include "queue.h"
/**
* Queue_Init - init a queue
* @q: pointer of queue
* @size: size of buffer in queue
*
* Must be called when started.
*/
void Queue_Init(Queue *q, int size)
{
q->buf = (unsigned char *)malloc(sizeof(unsigned char) * size);
memset(q->buf, 0x00, size);
q->read = 0;
q->write = 0;
q->size = size;
q->space = size;
q->OverFlow = false;
}
/**
* Queue_Destroy - destroy a queue
* @q: pointer of queue
*/
void Queue_Destroy(Queue *q)
{
free(q->buf);
}
/**
* Queue_Empty - tests whether a queue is empty
* @q: the queue to test
*/
bool Queue_Empty(Queue *q)
{
return (q->space == q->size);
}
/**
* Queue_Full - tests whether a queue is full
* @q: the queue to test
*/
bool Queue_Full(Queue *q)
{
return (q->space == 0);
}
/**
* AddQueue - add a byte to queue
* @q: the queue to add to
* @val: the char to add
*/
bool
bool AddQueue(Queue *q, unsigned char val)
{
if (!Queue_Full(q)) {
q->buf[q->write] = val;
q->write = (q->write + 1) % q->size;
q->space--;
return true;
}
return false;
}
/**
* DelQueue - delete a byte from queue
* @q: the queue to delete from
* @val: the char deleted
*/
bool DelQueue(Queue *q, unsigned char *val)
{
if (!Queue_Empty(q)) {
*val = q->buf[q->read];
q->read = (q->read + 1) % q->size;
q->space++;
return true;
}
return false;
}
/**
* WriteQueue - write buffers to queue
* @q: the queue to write in
* @buf: pointer of write buffer
* @len: length of write buffer
*/
unsigned int WriteQueue(Queue *q, unsigned char *buf, unsigned int len)
{
unsigned int ret = 0;
unsigned int rest = q->size - q->write;
if (!Queue_Full(q)) {
if (q->space >= len) {
ret = len;
if (rest >= len) {
memcpy(q->buf + q->write, buf, len);
q->write = (q->write + len) % q->size;
q->space -= len;
} else {
memcpy(q->buf + q->write, buf, rest);
q->write = 0;
memcpy(q->buf, buf + rest, len - rest);
q->write = len -rest;
q->space -= len;
}
} else {
ret = q->space;
if (rest >= q->space) {
memcpy(q->buf + q->write, buf, q->space);
q->write = (q->write + q->space) % q->size;
q->space = 0;
} else {
memcpy(q->buf + q->write, buf, rest);
q->write = 0;
memcpy(q->buf, buf + rest, q->space - rest);
q->write = q->space -rest;
q->space = 0;
}
}
}
return ret;
}
/**
* RecoverReadQueue - recover len of buffer from queue
* @q: the queue to recover from
* @len: recover length
*/
unsigned int RecoverReadQueue(Queue *q, unsigned int len)
{
unsigned int ret = 0;
unsigned int rest = q->read;
if (rest >= len)
{
q->read -= len;
}
else
{
q->read = q->size - (len - rest);
}
q->space -= len;
return ret;
}
/**
* ReadQueue - read buffers from queue
* @q: the queue to read from
* @buf: pointer of read buffer
* @len: read length
*/
unsigned int ReadQueue(Queue *q, unsigned char *buf, unsigned int len)
{
unsigned int rest = q->size - q->read;
unsigned int ret = 0;
if (!Queue_Empty(q)) {
if (Avail(q) >= len) {
ret = len;
if (rest >= len) {
memcpy(buf, q->buf + q->read, len);
q->read = (q->read + len) % q->size;
q->space += len;
} else {
memcpy(buf, q->buf + q->read, rest);
q->read = 0;
memcpy(buf + rest, q->buf, len - rest);
q->read = len -rest;
q->space += len;
}
return len;
} else {
ret = Avail(q);
if (rest >= Avail(q)) {
memcpy(buf, q->buf + q->read, Avail(q));
q->read = (q->read + Avail(q)) % q->size;
q->space = q->size;
} else {
memcpy(buf, q->buf + q->read, rest);
q->read = 0;
memcpy(buf + rest, q->buf, Avail(q) - rest);
q->read = Avail(q) -rest;
q->space = q->size;
}
}
}
return ret;
}
关于循环队列主题的系列文章,可移步至以下链接:
1. 《循环队列及C语言实现<一>》
2. 《循环队列及C语言实现<二>》
3. 《循环队列及C语言实现<三>》