1. 程式人生 > >如何利用記憶體池和共享記憶體構建高速的程序間通訊模型

如何利用記憶體池和共享記憶體構建高速的程序間通訊模型

#include "messagequeue.h"

#include 

BYTE* CMssageQueue::mpCurrAddr = nullptr;

CMssageQueue::CMssageQueue()
{
    miBegin = 0;
    miEnd = 0;
    miOffset = sizeof(this);
}

CMssageQueue::~CMssageQueue()
{

}

void *CMssageQueue::operator new(size_t size)
{
    return (void*)mpCurrAddr;
}

CMssageQueue* CMssageQueue::CreateInstance()
{
    return new CMssageQueue();
}
void CMssageQueue::SendMessage(char *message,int length)
{
    int nTempMaxLength = 0;
    int nTempRt = -1;
    BYTE *pbyCodeBuf;

    BYTE *pTempSrc = NULL;
    BYTE *pTempDst = NULL;
    unsigned int i;

    if( !message || length <= 0 )
    {
        return;
    }

    pbyCodeBuf = MessageBeginAddr();
    // 首先判斷是否佇列已滿
    if(IsMemFull())		//if( m_stQueueHead.m_nFullFlag )
    {
        return;
    }

    nTempMaxLength  = GetFreeSize();

    nTempRt = miEnd;

    //空間不足
    if((length + sizeof(unsigned short) )> nTempMaxLength)
    {
        return;
    }

    unsigned short usInLength = (unsigned short) length;

    pTempDst = &pbyCodeBuf[0];
    pTempSrc = (BYTE*) (&usInLength);

    //寫入的時候我們在資料頭插上資料的長度,方便準確取資料
    for( i = 0; i < sizeof(usInLength); i++ )
    {
        pTempDst[miEnd] = pTempSrc[i];  // 拷貝 Code 的長度
        miEnd = (miEnd + 1) % GetDataMemSize();  // % 用於防止 Code 結尾的 idx 超出 codequeue
    }

    //空閒區在中間
    if( miBegin > miEnd )
    {
        memcpy((void *)&pbyCodeBuf[miEnd], (const void *)message, (size_t)usInLength );
    }
    else   //空閒區在兩頭
    {
        //尾部放不下需要分段拷貝的情況
        if( length > (GetDataMemSize() - miEnd) )
        {
            memcpy((void *)&pbyCodeBuf[miEnd], (const void *)&message[0], (size_t)(GetDataMemSize()- miEnd) );
            memcpy((void *)&pbyCodeBuf[0],(const void *)&message[(GetDataMemSize() - miEnd)],
                   (size_t)(length - (GetDataMemSize() - miEnd)));
        }
        else
        {
            memcpy((void *)&pbyCodeBuf[miEnd], (const void *)&message[0], (size_t)length);
        }
    }
    miEnd = (miEnd + length) % GetDataMemSize();
}

int CMssageQueue::GetMessage(BYTE *pOutCode, int *pOutLength)
{
    int nTempMaxLength = 0;
    int nTempRet = -1;
    BYTE *pTempSrc;
    BYTE *pTempDst;
    unsigned int i;
    BYTE *pbyCodeBuf;

    if( !pOutCode || !pOutLength )
    {
        return -1;
    }

    nTempMaxLength = GetDataSize();
    if (nTempMaxLength <= 0) {
        return -1;
    }

    pbyCodeBuf = MessageBeginAddr();

    nTempRet = miBegin;

    // 如果資料的最大長度不到2(存入資料時在資料頭插入了資料的長度)
    if( nTempMaxLength < (int)sizeof(short) )
    {
        miBegin = miEnd;
        return -1;
    }

    unsigned short usOutLength;
    pTempDst = (BYTE *)&usOutLength;   // 資料拷貝的目的地址
    pTempSrc = (BYTE *)&pbyCodeBuf[0];  // 資料拷貝的源地址
    //取出資料的長度
    for( i = 0; i < sizeof(short); i++ )
    {
        pTempDst[i] = pTempSrc[miBegin];
        miBegin = (miBegin+1) % GetDataMemSize();
    }

    // 將資料長度回傳
    *pOutLength = usOutLength;
    //資料的長度非法
    if(usOutLength > (int)(nTempMaxLength - sizeof(short)) || usOutLength < 0 )
    {
        miBegin = miEnd;
        return -1;
    }

    pTempDst = (BYTE *)&pOutCode[0];  // 設定接收 Code 的地址
    // 資料在中間
    if( miBegin < miEnd )
    {
        memcpy((void *)pTempDst, (const void *)&pTempSrc[miBegin], (size_t)(usOutLength));
    }
    else
    {
        if(GetDataMemSize() - miBegin < usOutLength)
        {
            memcpy((void *)pTempDst, (const void *)&pTempSrc[miBegin], (size_t)(GetDataMemSize() - miBegin));
            pTempDst += (GetDataMemSize() - miBegin);
            memcpy((void *)pTempDst, (const void *)&pTempSrc[0], (size_t)(usOutLength - (GetDataMemSize() - miBegin)));
        }
        else	// 否則,直接拷貝
        {
            memcpy((void *)pTempDst, (const void *)&pTempSrc[miBegin], (size_t)(usOutLength));
        }
    }
    miBegin = (miBegin + usOutLength) % GetDataMemSize();
    return usOutLength;
}

BYTE* CMssageQueue::MessageBeginAddr()
{
    return (BYTE*)(this + miOffset);
}


bool CMssageQueue::IsMemFull()
{
    return GetFreeSize() <= 0;
}

//獲取空閒區大小
int CMssageQueue::GetFreeSize()
{
    int freesize = 0;
    //第一次寫資料前
    if( miBegin == miEnd )
    {
        freesize = GetDataMemSize();
    }
        //資料在兩頭
    else if( miBegin > miEnd )
    {
        freesize = miBegin - miEnd;
    }
    else   //資料在中間
    {
        freesize = freesize - (miEnd - miBegin);
    }
    //長度應該減去預留部分長度8,保證首尾不會相接
    freesize -= EXTRA_BYTE;
    return freesize;
}

//獲取資料長度
int CMssageQueue::GetDataSize()
{
    int freesize = GetDataMemSize();
    //第一次寫資料前
    if( miBegin == miEnd )
    {
        return 0;
    }
        //資料在兩頭
    else if( miBegin > miEnd )
    {
        return freesize - (miBegin - miEnd);
    }
    else   //資料在中間
    {
        return  miEnd - miBegin;
    }
}

int CMssageQueue::GetDataMemSize()
{
    return (int)(MEM_SIZE - sizeof(this));
}