头文件:
////////////////////////////////////////////////////////// // 文件名: 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; }