在WINCE开发中很多时候需要用到循环队列来缓存数据,比如在串口通信中,可以将接收到的数据流先缓存到循环队列中,然后再从循环队列中取出数据做下一步的处理。这样可以有效的避免解析数据帧时繁琐的拼接处理。
为了方便使用,封装了一个循环队列类,具体代码如下:
头文件:
/********************************************************************
filename: CircularQueue.h
created: 2011-08-23
author: firehood
purpose: 实现循环队列
队列可以缓存的数据大小 = 队列长度 -1
插入数据时在队列满的情况下会自动覆盖队列头部数据
*********************************************************************/
#pragma once
#define DEFAULT_QUEUE_MAX_SIZE 512
class CCircularQueue
{
public:
// 无参构造函数,默认创建队列的大小为512字节
CCircularQueue(void);
// 带参构造函数,创建指定大小的队列
CCircularQueue(int nQueueSize);
~CCircularQueue(void);
public:
// 向队列尾部插入一个字节,队列满时会自动覆盖队列头部数据
bool PushBack(unsigned char data);
// 从队列头部取出一个字节
bool PopFront(unsigned char &data);
// 向队列尾部插入指定长度数据,队列满时会自动覆盖队列头部数据
bool PushBack(unsigned char *pData, int size);
// 从队列头部取出指定长度数据
// 返回值:>0 返回实际取出的数据长度; <=0 失败
int PopFront(unsigned char *pData, int size);
// 重新调整队列大小
bool Resize(int nQueueSize);
// 当前队列缓存的数据大小
int Size();
// 队列当前剩余空间大小
int RemainSize();
// 队列是否为空
bool IsEmpty();
// 队列是否满
bool IsFull();
// 打印数据(测试使用)
void PrintData();
private:
unsigned char *m_pQueueBase; // 队列基址
int m_QueueSize; // 队列大小
int m_Head, m_Tail; // 队列头尾指针
CRITICAL_SECTION m_csRW; // 读写锁
};
源文件:
/********************************************************************
filename: CircularQueue.cpp
created: 2011-08-23
author: firehood
purpose: 实现循环队列
队列可以缓存的数据大小 = 队列长度 -1
插入数据时在队列满的情况下会自动覆盖队列头部数据
*********************************************************************/
#include "stdafx.h"
#include "CircularQueue.h"
CCircularQueue::CCircularQueue(void):
m_pQueueBase(NULL),
m_Head(0),
m_Tail(0),
m_QueueSize(DEFAULT_QUEUE_MAX_SIZE)
{
m_pQueueBase = new unsigned char[m_QueueSize];
ASSERT(m_pQueueBase);
memset(m_pQueueBase, 0, m_QueueSize);
InitializeCriticalSection(&m_csRW);
}
CCircularQueue::CCircularQueue(int nQueueSize):
m_pQueueBase(NULL),
m_Head(0),
m_Tail(0),
m_QueueSize(nQueueSize)
{
m_pQueueBase = new unsigned char[m_QueueSize];
ASSERT(m_pQueueBase);
memset(m_pQueueBase, 0, m_QueueSize);
InitializeCriticalSection(&m_csRW);
}
CCircularQueue::~CCircularQueue(void)
{
if(m_pQueueBase)
{
delete[] m_pQueueBase;
m_pQueueBase = NULL;
}
DeleteCriticalSection (&m_csRW);
}
// 向队列尾部插入一个字节,队列满时会自动覆盖队列头部数据
bool CCircularQueue::PushBack(unsigned char data)
{
if(m_pQueueBase == NULL)
{
return false;
}
EnterCriticalSection(&m_csRW);
m_pQueueBase[m_Tail]= data;
m_Tail =(m_Tail+1) % m_QueueSize;
if(m_Tail == m_Head)
{
m_Head = m_Tail+1;
printf("Warning:lost data, Queue is full..\n");
}
LeaveCriticalSection(&m_csRW);
return true;
}
// 从队列头部取出一个字节
bool CCircularQueue::PopFront(unsigned char &data)
{
if(m_pQueueBase == NULL)
{
return false;
}
if(IsEmpty())
{
return false;
}
EnterCriticalSection(&m_csRW);
data = m_pQueueBase[m_Head];
m_Head=(m_Head+1) % m_QueueSize;
LeaveCriticalSection(&m_csRW);
return true;
}
// 向队列尾部插入指定长度数据,队列满时会自动覆盖队列头部数据
bool CCircularQueue::PushBack(unsigned char *pData, int size)
{
if(m_pQueueBase == NULL || pData == NULL)
{
return false;
}
if(size >= m_QueueSize)
{
printf("PushBack failed: DataSize[%d] > MAX_QUEUE_SIZE[%d]\n" , size, (m_QueueSize-1));
return false;
}
EnterCriticalSection(&m_csRW);
int nRemianSize = RemainSize();
int nTailToEndSize = m_QueueSize - m_Tail;
if(size <= nTailToEndSize)
{
memcpy(m_pQueueBase+m_Tail, pData, size);
}
else
{
memcpy(m_pQueueBase+m_Tail, pData, nTailToEndSize);
memcpy(m_pQueueBase,pData+nTailToEndSize, size-nTailToEndSize);
}
m_Tail = (m_Tail+size) % m_QueueSize;
if(size >= nRemianSize)
{
printf("Warning:lost data, Queue is full..\n");
m_Head = m_Tail+1;
}
LeaveCriticalSection(&m_csRW);
return true;
}
// 从队列头部取出指定长度数据
// 返回值:>0 返回实际取出的数据长度; <=0 失败
int CCircularQueue::PopFront(unsigned char *pData, int size)
{
if(pData == NULL || m_pQueueBase == NULL)
return -1;
EnterCriticalSection(&m_csRW);
int nReadSize = (this->Size()>size) ? size : this->Size();
int nHeadToEndSize = m_QueueSize - m_Head;
if(nReadSize <= nHeadToEndSize)
{
memcpy(pData, m_pQueueBase+m_Head, nReadSize);
}
else
{
memcpy(pData,m_pQueueBase+m_Head, nHeadToEndSize);
memcpy(pData+nHeadToEndSize,m_pQueueBase,nReadSize-nHeadToEndSize);
}
m_Head=(m_Head+nReadSize) % m_QueueSize;
LeaveCriticalSection(&m_csRW);
return nReadSize;
}
// 当前队列缓存的数据大小
int CCircularQueue::Size()
{
return (m_Tail-m_Head+m_QueueSize) % m_QueueSize;
}
// 队列是否为空
bool CCircularQueue::IsEmpty()
{
return (m_Head == m_Tail) ? true : false;
}
// 队列是否满
bool CCircularQueue::IsFull()
{
return (((m_Tail+1) % m_QueueSize) == m_Head) ? true : false;
}
// 队列当前剩余空间大小
int CCircularQueue::RemainSize()
{
return ((m_QueueSize-1)-Size());
}
// 打印数据
void CCircularQueue::PrintData()
{
int tempHead, tempTail;
tempHead = m_Head;
tempTail = m_Tail;
printf("************************************************\n");
printf("CirualarQueue Data:");
while(tempHead != tempTail)
{
printf("0x%02x ", m_pQueueBase[tempHead]);
tempHead=(tempHead+1) % m_QueueSize;
}
printf("\n");
printf("************************************************\n");
}
// 重新调整队列大小
bool CCircularQueue::Resize(int nQueueSize)
{
unsigned char *pNewQueue = NULL;
// 申请新的队列空间
pNewQueue = new unsigned char[nQueueSize];
if(pNewQueue == NULL) // 申请内存失败
return false;
// 将队列原有数据拷贝到新队列中
int len = PopFront(pNewQueue,nQueueSize);
// 释放原来队列空间
if(m_pQueueBase)
{
delete[] m_pQueueBase;
m_pQueueBase = NULL;
}
// 使用新的队列空间
m_pQueueBase = pNewQueue;
m_QueueSize = nQueueSize;
m_Head = 0;
m_Tail = len;
return true;
}