c++メモリプールの実装(new複雑なオブジェクトが可能)

17789 ワード

/*
        :
            1>.    Malloc()/Free()/Mempool_new()/Mempool_delete()         malloc()/free()    new()/delete()
            2>.   qt     #define QT   
            3>.   win32        
            4>.   linux c/c++(      )  pthread    _Lock   

        :
            1>.  Mempool_new        new   ,                0~4   ,            ,           .
            2>.             volatile/const   ,           .

         :
            CMemoryPool<:list> myMemPool;
            std::List* pLst = myMemPool.Mempool_new();//    ,      .
            struct mySimpleStruct* pStru = myMemPool.Malloc(sizeof(mySimpleStruct));//    .
*/

#ifndef MEMORYPOOL_HPP
#define MEMORYPOOL_HPP

//#define QT //   windows           

#include 
#include 
#include 

#ifndef QT
#include 
#else
#include 
#endif

using namespace std;

#define IN 
#define OUT 
#define MAX_BLOCK_TYPE              16
#define MAX_UNIT_NUM                1024

#ifndef QT
class _Lock
{
public:
    _Lock(void)
    {
        InitializeCriticalSection(&m_csLock);
    }
    ~_Lock(void)
    {
        DeleteCriticalSection(&m_csLock);
    }

    inline void Lock()
    {
        EnterCriticalSection(&m_csLock);
    }
    inline void UnLock()
    {
        LeaveCriticalSection(&m_csLock);
    }

protected:
    CRITICAL_SECTION    m_csLock;
};
#else
class _Lock
{
public:
    _Lock(void)
    {
        //do nothing
    }
    ~_Lock(void)
    {
        //do nothing
    }

    inline void Lock()
    {
        m_mxLock.lock();
    }
    inline void UnLock()
    {
        m_mxLock.unlock();
    }

protected:
    QMutex  m_mxLock;
};
#endif

typedef struct MEM_BLOCK
{
    struct MEM_BLOCK    *m_pNext;
    _Lock               m_csLock;
    deque<char*>        m_dqAddr;
    int                 m_iUnitSize;
    char                *m_pBuffer;

    MEM_BLOCK(IN const int iUnitSize)
    {
        m_pNext = NULL;

        m_iUnitSize = iUnitSize;

        m_pBuffer = new (std::nothrow)char[iUnitSize * MAX_UNIT_NUM];

        for (int i = 0; i < MAX_UNIT_NUM; i ++)
            m_dqAddr.push_back(m_pBuffer + i * iUnitSize);

        return ;
    }

    ~MEM_BLOCK()
    {
        m_pNext = NULL;

        delete [] m_pBuffer;

        m_dqAddr.clear();

        return ;
    }
} MEM_BLOCK, *LPMEM_BLOCK;

typedef struct MEM_POOL
{
    _Lock               m_csLock;
    LPMEM_BLOCK         m_pMemBlock[MAX_BLOCK_TYPE];
    int                 m_iUnitSize[MAX_BLOCK_TYPE];
    int                 m_iBlockNum[MAX_BLOCK_TYPE];
    int                 m_iUsedMem;

    MEM_POOL()
    {
        ZeroMemory(m_pMemBlock, sizeof(m_pMemBlock));
        ZeroMemory(m_iUnitSize, sizeof(m_iUnitSize));
        ZeroMemory(m_iBlockNum, sizeof(m_iBlockNum));
        m_iUsedMem = 0;
    }
} MEM_POOL, *LPMEM_POOL;

template <class T>
class CMemoryPool
{
public:
    CMemoryPool(void);
    virtual ~CMemoryPool(void);

    void SetUseMemLimte(IN const int iMaxUseMem);

    inline T* Mempool_new()
    {
        T* const p = (T*)Malloc(sizeof(T));
        if (p == 0)
            return p;
        try
        {
            new (p)T();
        }
        catch (...)
        {
            (free)(p);
            throw;
        }
        return p;
    }

    template <typename T0>
    inline T* Mempool_new(IN const T0 & a0)
    {
        T* const p = (T*)Malloc(sizeof(T));
        if (p == 0)
            return p;
        try
        {
            new (p)T(a0);
        }
        catch (...) 
        {
            (free)(p);
            throw;
        }
        return p;
    }

    template <typename T0, typename T1>
    inline T* Mempool_new(IN const T0 & a0,IN const T1 & a1)
    {
        T* const p = (T*)Malloc(sizeof(T));
        if (p == 0)
            return p;
        try
        { 
            new (p)T(a0, a1);
        }
        catch (...)
        {
            (free)(p);
            throw;
        }
        return p;
    }

    template <typename T0, typename T1, typename T2>
    inline T* Mempool_new(IN const T0 & a0,IN const T1 & a1,IN const T2 & a2)
    {
        T* const p = (T*)Malloc(sizeof(T));
        if (p == 0)
            return p;
        try 
        {
            new (p)T(a0, a1, a2);
        }
        catch (...)
        { 
            (free)(p); 
            throw;
        }
        return p;
    }

    template <typename T0, typename T1, typename T2, typename T3>
    inline T* Mempool_new(IN const T0 & a0,IN const T1 & a1,IN const T2 & a2,IN const T3 & a3)
    {
        T* const p = (T*)Malloc(sizeof(T));
        if (p == 0)
            return p;
        try
        {
            new (p)T(a0, a1, a2, a3);
        }
        catch (...)
        {
            (free)(p);
            throw;
        }
        return p;
    }

    void Mempool_delete(IN T* p);
    void* Malloc(IN const int iLen);
    void Free(IN void* p);
    bool IsEmpty();

protected:
    MEM_POOL            m_MemPool;
    _Lock               m_csMapLock;
    map<void*, void*>   m_mapMalloc;
    int                 m_iMaxUseMem;
};

template<class T>
CMemoryPool::CMemoryPool(void)
{
    m_iMaxUseMem = 0;
    m_mapMalloc.clear();

    for (int i = 0; i < MAX_BLOCK_TYPE; i++)
        m_MemPool.m_iUnitSize[i] = 16 << i;

    return;
}

template<class T>
CMemoryPool::~CMemoryPool(void)
{
    //       
    for (int i = 0; i < MAX_BLOCK_TYPE; i++)
    {
        LPMEM_BLOCK p1 = NULL;
        LPMEM_BLOCK p = m_MemPool.m_pMemBlock[i];
        while (p)
        {
            p1 = p->m_pNext;
            delete p;
            p = p1;
        }
    }

    return;
}

template<class T>
void CMemoryPool::SetUseMemLimte(IN int iMaxUseMem)
{
    m_iMaxUseMem = iMaxUseMem;

    return;
}

template <class T>
void CMemoryPool::Mempool_delete(IN T* p)
{
    //      
    p->~T();
    //       
    Free(p);
}

template<class T>
void* CMemoryPool::Malloc(IN int iLen)
{
    void *p = NULL;

    int i = 0;
    for (; i < MAX_BLOCK_TYPE; i++)
    {
        if (iLen < m_MemPool.m_iUnitSize[i])
            break;
    }

    //           
    if (i == MAX_BLOCK_TYPE)
        return p;

    //        
    m_MemPool.m_csLock.Lock();
    if (!m_MemPool.m_pMemBlock[i])
    {
        m_MemPool.m_pMemBlock[i] = new (std::nothrow)MEM_BLOCK(m_MemPool.m_iUnitSize[i]);
        if (m_MemPool.m_pMemBlock[i])
            m_MemPool.m_iUsedMem += m_MemPool.m_iUnitSize[i] * MAX_UNIT_NUM;
    }
    m_MemPool.m_csLock.UnLock();

    LPMEM_BLOCK pB = m_MemPool.m_pMemBlock[i];
    if (!pB)
        return p;

    while (pB)
    {
        pB->m_csLock.Lock();
        if (pB->m_dqAddr.size())
        {
            //    
            p = (void*)pB->m_dqAddr.front();
            pB->m_dqAddr.pop_front();
            pB->m_csLock.UnLock();

            //      
            m_csMapLock.Lock();
            m_mapMalloc[p] = (void*)pB;
            m_csMapLock.UnLock();

            break;
        }

        //         
        if (!pB->m_pNext)
        {
            //         
            if (m_iMaxUseMem && m_MemPool.m_iUsedMem + m_MemPool.m_iUnitSize[i] * MAX_UNIT_NUM > m_iMaxUseMem)
            {
                //     
                pB->m_csLock.UnLock();
                break;
            }

            pB->m_pNext = new (std::nothrow)MEM_BLOCK(m_MemPool.m_iUnitSize[i]);
            if (!pB->m_pNext)
            {
                //     
                pB->m_csLock.UnLock();
                break;
            }

            m_MemPool.m_iUsedMem += m_MemPool.m_iUnitSize[i] * MAX_UNIT_NUM;
        }

        pB->m_csLock.UnLock();
        pB = pB->m_pNext;
    }

    return p;
}

template<class T>
void CMemoryPool::Free(IN void *p)
{
    LPMEM_BLOCK pB = NULL;

    //         
    m_csMapLock.Lock();
    map<void*, void*>::iterator it = m_mapMalloc.find(p);
    if (it != m_mapMalloc.end())
    {
        pB = (LPMEM_BLOCK)it->second;
        m_mapMalloc.erase(it);
    }
    m_csMapLock.UnLock();

    if (!pB)
        return;

    pB->m_csLock.Lock();
    memset(p, 0, pB->m_iUnitSize);
    pB->m_dqAddr.push_back((char*)p);
    pB->m_csLock.UnLock();

    return;
}

template<class T>
bool CMemoryPool::IsEmpty()
{
    return m_mapMalloc.size() == 0;
}

#endif //MEMORYPOOL_HPP