头文件:
//
// 文件名: MessageQueue.h
// 版本: 1.0
// 目的及主要功功能: 消息队列CMessageQueue
// 创建日期: 2009.05.05
// 修改日期:
// 作者:
// 修改:
//
#pragma once
#include "afx.h"
const int MSG_QUEUE_MIN_SIZE = 2 * 1024 * 1024; //消息队列缓冲区的最小值,2M
const SHORT MAX_EVENT_DATA_LEN = 2 * 1024; //最大事件数据长度2K
typedef struct tagAlarmStructure
{
CHAR cUse[MAX_EVENT_DATA_LEN - 1];
}AlarmStructure, *LPAlarmStructure;
//消息队列的成员结构
typedef struct tagMSG_QUEUE_MEMBER
{
USHORT usOldEventType; //原始事件类型
USHORT usNewEventType; //PostMessage使用的事件消息类型
USHORT usResultValue; //部分事件的返回值,多为失败原因
AlarmStructure MsgData; //事件返回的数据
}MSG_QUEUE_MEMBER, *PMSG_QUEUE_MEMBER;
class CMessageQueue :
public CObject
{
public:
//临界区对象
CRITICAL_SECTION m_csMsgQueue;
//构造函数
CMessageQueue(int iMaxMsgQueueSize);
~CMessageQueue(void);
//返回消息队列中消息的个数
int GetMsgCount();
//向队列中保存一条消息
int SendMessage(int iMsgLen, CHAR* pMsgData);
//从队列中取出一条消息
int GetMessage(int* iMsgLen, CHAR* pMsgData);
private:
int m_iMaxBufferSize; //最大允许提交的消息队列缓冲区长度
int m_iMsgNum; //队列中的消息个数
CHAR* m_pQueueData; //存放消息的缓冲区
CHAR* m_pEndPoint; //队列尾指针
CHAR* m_pReadPoint; //队列读指针
CHAR* m_pWritePoint; //队列写指针
};
源文件:
//
// 文件名: MessageQueue.cpp
// 版本: 1.0
// 目的及主要功功能: 消息队列CMessageQueue
// 创建日期: 2009.05.05
// 修改日期:
// 作者:
// 修改:
//
#include "StdAfx.h"
#include "messagequeue.h"
CMessageQueue::CMessageQueue(int iMaxMsgQueueSize)
{
//创建临界区,用于多个线程对队列的互斥访问
InitializeCriticalSection(&m_csMsgQueue);
//如果指定的大小小于允许的最小值,调整大小
if (iMaxMsgQueueSize < MSG_QUEUE_MIN_SIZE)
{
m_iMaxBufferSize = MSG_QUEUE_MIN_SIZE;
}
else
{
m_iMaxBufferSize = iMaxMsgQueueSize;
}
//为队列缓冲区分配内存,如果分配内存失败,返回
m_pQueueData = new CHAR[m_iMaxBufferSize];
if(NULL == m_pQueueData)
{
return;
}
//初始化尾指针,读指针,写指着,消息个数
m_pEndPoint = m_pQueueData + m_iMaxBufferSize;
m_pReadPoint = m_pQueueData;
m_pWritePoint = m_pQueueData;
m_iMsgNum = 0;
}
CMessageQueue::~CMessageQueue(void)
{
//释放队列缓冲区内存
delete [] m_pQueueData;
m_pQueueData = NULL;
//释放临界区对象
DeleteCriticalSection(&m_csMsgQueue);
}
//返回消息队列中消息的个数
int CMessageQueue::GetMsgCount()
{
int iMsgNum = 0;
//首先进入临界区,对队列进行独占式访问
EnterCriticalSection(&m_csMsgQueue);
//取队列中消息个数
iMsgNum = m_iMsgNum;
//退出临界区,允许其他线程访问消息队列
LeaveCriticalSection(&m_csMsgQueue);
return iMsgNum;
}
//=======================================================
// 函 数 名:GetMessage
// 功能描述:从队列中取一个消息
// 输入参数:无
// 输出参数:iMsgLen: 消息长度
// pMsgData 存放消息数据缓冲区
// 返回参数:成功是0,失败为1
// 创建日期:2009.05.05
// 修改日期:2009.05.05
// 作 者:
//========================================================
int CMessageQueue::GetMessage(int* iMsgLen, CHAR* pMsgData)
{
ULONG ulLen = 0;
ULONG ulLength ;
CHAR* pLen = (CHAR*)&ulLength;
//对输入参数的有效性进行检查
if (NULL == pMsgData)
{
return 1;
}
//进入临界区,独占式访问消息队列
EnterCriticalSection(&m_csMsgQueue);
//如果读指针和写指针相同,队列中没有消息可读,退出临界区,返回
if (m_pWritePoint == m_pReadPoint)
{
LeaveCriticalSection(&m_csMsgQueue);
//WriteLog(('TMsgQueue.GetMessage:Queue is null'")
return 1;
}
ulLen = (ULONG)(m_pEndPoint - m_pReadPoint );
//存放当前消息长度的那个ULONG没有被分隔
if (ulLen >= sizeof(ULONG))
{
//ulLen中存放了消息长度
memcpy(pLen, m_pReadPoint, sizeof(ULONG));
m_pReadPoint = m_pReadPoint + sizeof(ULONG);
//m_pReadPoint指向消息的首字节
ulLen = (ULONG)(m_pEndPoint - m_pReadPoint);
//消息没有被分隔,直接复制Length字节到pMsgData中
if (ulLen >= ulLength)
{
memcpy(pMsgData, m_pReadPoint, ulLength);
m_pReadPoint = m_pReadPoint + ulLength;
}
//消息被分隔,需要先复制队列尾部的ulLen字节,再从头部复制ulLength-ulLen字节
else
{
memcpy(pMsgData, m_pReadPoint, ulLen);
memcpy(pMsgData + ulLen, m_pQueueData, ulLength - ulLen);
m_pReadPoint = m_pQueueData + ulLength - ulLen;
}
}
//存放当前消息长度的那个ULONG被分隔
else
{
//得到消息长度
memcpy(pLen, m_pReadPoint, ulLen);
pLen = pLen + ulLen;
memcpy(pLen, m_pQueueData,sizeof(ULONG) - ulLen);
//把m_pReadPoint指向消息的首字节
//消息长度不会超过队列缓冲区的长度,否则消息队列太小
m_pReadPoint = m_pQueueData + sizeof(ULONG) - ulLen;
memcpy(pMsgData, m_pReadPoint, ulLength) ;
m_pReadPoint = m_pReadPoint + ulLength;
}
//设置输出参数:消息长度
*iMsgLen = ulLength;
//取走了一个消息,消息个数减少
m_iMsgNum = m_iMsgNum - 1;
//退出临界区,允许其他线程访问消息队列
LeaveCriticalSection(&m_csMsgQueue);
return 0;
}
//=======================================================
// 函 数 名:SendMessage
// 功能描述:向队列中发送一个消息
// 输入参数:iMsgLen: 消息长度
// pMsgData 存放消息数据缓冲区
// 输出参数:无
// 返回参数:成功是0,失败为1
// 创建日期:2009.05.05
// 修改日期:2009.05.05
// 作 者:
//========================================================
int CMessageQueue::SendMessage(int iMsgLen, CHAR* pMsgData)
{
// ULONG* pulLen = NULL;
PULONG pulLen;
ULONG ulLenF = 0;
ULONG ulLenS = 0;
ULONG ulLenLeft = 0;
int iFirstCopyLen = 0;
CHAR* pszLen = NULL;
int iRet = 0;
//对输入参数的有效性进行检查
if (NULL == pMsgData && iMsgLen <= 0)
{
return 1;
}
//进入临界区,独占式访问消息队列
EnterCriticalSection(&m_csMsgQueue);
//读指针在前,写指针在后
if (m_pWritePoint >= m_pReadPoint)
{
//在队列尾部就能保存这条消息
if ((ULONG)(m_pEndPoint - m_pWritePoint) > (ULONG)(iMsgLen + sizeof(ULONG)))
{
pulLen = PULONG(m_pWritePoint);
//首先保存消息的长度
*pulLen = iMsgLen;
m_pWritePoint = m_pWritePoint + sizeof(ULONG);
memcpy(m_pWritePoint, pMsgData, iMsgLen);
m_pWritePoint = m_pWritePoint + iMsgLen;
m_iMsgNum = m_iMsgNum + 1;
}
else
{
//队尾+队头的空间能够保存这条消息
if ((ULONG)(m_pEndPoint - m_pWritePoint) + (ULONG)(m_pReadPoint - m_pQueueData)
> (ULONG)(iMsgLen + sizeof(ULONG)))
{
//队尾能够存放消息长度ULONG
if ((m_pEndPoint - m_pWritePoint) > sizeof(ULONG))
{
pulLen = PULONG(m_pWritePoint);
//首先保存消息的长度
*pulLen = iMsgLen;
//队尾还剩下的字节数
ulLenF = (ULONG)(m_pEndPoint - m_pWritePoint - sizeof(ULONG));
//队头需要占用的字节数
ulLenS = (ULONG)iMsgLen - ulLenF;
//Begin: Modified by Wu Guangya, 2009/5/23
//m_pWritePoint = m_pWritePoint + ulLenS;
m_pWritePoint = m_pWritePoint + sizeof(ULONG);
//End: Modified by Wu Guangya, 2009/5/23
memcpy(m_pWritePoint, pMsgData, ulLenF);
m_pWritePoint = m_pQueueData;
memcpy(m_pWritePoint, pMsgData + ulLenF, ulLenS);
m_pWritePoint = m_pWritePoint + ulLenS;
m_iMsgNum = m_iMsgNum + 1;
}
//消息长度需要分隔保存在队尾和队头
else
{
iFirstCopyLen = (int)(m_pEndPoint - m_pWritePoint);
pszLen = (CHAR*)(&iMsgLen);
memcpy(m_pWritePoint, pszLen, iFirstCopyLen);
ulLenLeft = sizeof(ULONG) - iFirstCopyLen;
m_pWritePoint = m_pQueueData;
memcpy(m_pWritePoint, pszLen + iFirstCopyLen, ulLenLeft);
m_pWritePoint = m_pWritePoint + ulLenLeft;
memcpy(m_pWritePoint, pMsgData, iMsgLen);
m_pWritePoint = m_pWritePoint + iMsgLen;
m_iMsgNum = m_iMsgNum + 1;
}
}
//队尾+队头的空间不能够存放这条消息,队列满,无法保存消息
else
{
iRet = 1;
}
}
}
//写指针在前,读指针在后
else
{
//读/写指针之间的空间能够存放这条消息
if ((ULONG)(m_pReadPoint - m_pWritePoint) > (ULONG)(iMsgLen + sizeof(ULONG)))
{
pulLen = (ULONG*)m_pWritePoint;
*pulLen = iMsgLen;
memcpy(m_pWritePoint + sizeof(ULONG), pMsgData, iMsgLen);
m_pWritePoint = m_pWritePoint + iMsgLen + sizeof(ULONG);
m_iMsgNum = m_iMsgNum + 1;
}
//队列满,无法保存消息
//需要注意,“等于”的情况下能够存放消息,但存放后读指针和写指针相同
//会导致GetMessage函数认为队列为空
else
{
iRet = 1;
}
}
//退出临界区,允许其它线程访问消息队列
LeaveCriticalSection(&m_csMsgQueue);
return iRet;
}