在我的上一篇博文中已经讲到循环队列的特点作用以及C语言实现,当然实现和操作的方式比较简单,在实际项目应用中略显粗糙。因此,这一篇提供一个进阶篇的实现与操作接口。具体函数作用可以参见我的注释部分,使用的时候直接把里面的接口函数放在一个头文件里面直接调用就可以啦,十分方便易用,但是可以实现的功能不可小觑哦,比如我在写高速USB设备驱动(20MB/s)以及网络抓包缓存的时候用到的都是这个看似简单的数据结构,所以还没有熟练运用的要加把劲了。需要注意的地方包括:
<1> 不再利用上一篇中 “q->front = (q->rear + 1) % q->size” 的关系来进行队列空还是满的判断了,这次利用 space 剩余缓存空间大小来判断。
<2> 写缓冲区的时候,要进行缓冲区剩余空间大小 space 的判断,如果要写入空间小于等于剩余空间,那么就可以将数据完全写入缓冲区,此时写入长度等于要写入的数据长度,否则只能将部分数据写入缓冲区,返回长度就等于剩余空间大小了。
<3> 读缓冲区同理,要进行当前缓冲区中可用缓存的大小的判断,也即已写入缓存大小的判断。若要读出的数据长度小于已写入缓存,那么返回长度为希望读出的数据长度,否则为已写入缓存的长度。
<4> 在写入和读出的时候尤其需要注意到达缓冲区边界的时候,数据和读写位置的处理。如果读写到了边界,那么就要分两次读取了,另外读写位置一定不能超越分配的缓冲区边界,所以在循环队列中数据的读写位置前移的时候都要对缓冲区长度取余以保证数据操作的安全性。
下面就是代码部分了,若有不明或不妥之处,可以直接 send comments to me :-D
/*
* Queue operation API - 1.0
*
* Copyright (C) 2016 SoldierJazz ([email protected])
*
* This program is free software; you can redistribute it and/or
* modify it.
*
*/
#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 {
char *buf;
unsigned int read;
unsigned int write;
unsigned int size;
unsigned int space;
} Queue;
#define Avail(q) (q->size - q->space)
/**
* 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 = (char *)malloc(sizeof(char) * size);
q->read = 0;
q->write = 0;
q->size = size;
q->space = size;
}
/**
* 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 AddQueue(Queue *q, 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, 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
*/
static int WriteQueue(Queue *q, 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;
}
/**
* ReadQueue - read buffers from queue
* @q: the queue to read from
* @buf: pointer of read buffer
* @len: read length
*/
static int ReadQueue(Queue *q, 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;
}
void main()
{
int ret = 0;
char buf[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
char buf2[10];
Queue q;
Queue_Init(&q, 10);
ret = WriteQueue(&q, buf, 5);
printf("writed %d bytes.\n", ret);
ret = ReadQueue(&q, buf2, 2);
printf("readed %d bytes.\n", ret);
ret = WriteQueue(&q, buf, 10);
printf("writed %d bytes.\n", ret);
ret = ReadQueue(&q, buf2, 7);
printf("readed %d bytes.\n", ret);
ret = ReadQueue(&q, buf2, 7);
printf("readed %d bytes.\n", ret);
Queue_Destroy(&q);
}
运行结果如下:
关于循环队列主题的系列文章,可移步至以下链接:
1. 《循环队列及C语言实现<一>》
2. 《循环队列及C语言实现<二>》
3. 《循环队列及C语言实现<三>》