消息队列

头文件:

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



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值