多线程内存池实现代码-双链表

来源:互联网 发布:avmask永久域名 编辑:程序博客网 时间:2024/06/05 15:11

一下代码为一个简单的多线程内存池实现,内存池block块大小固定,采用双链表实现block申请、释放管理。

比较简单,参考注释和readme基本可以看懂,不多介绍了。

#ifndef _MEMPOOL_H_#define _MEMPOOL_H_/*Readme: * 1.内存池为多个相同大小的内存block集合,block大小和个数在初始化是设定。 * 2.用两个链表管理内存池的block集合,一个为空闲块链表(可申请),另一个为 *  待释放块链表,这两个链表均为带头结点的单向非循环链表。实现时只提供空闲 *  链表头和待释放链表头,具体链表节点为block管理节点(和block一一对应),每个 *  block管理节点内部包含block内存地址,大小和指向下一个管理节点的next指针。 * 3.申请时从空闲块链表上申请,若空闲块链表上已经没有空闲块,则将空闲块链表 *  和待释放块链表交换(加锁);若申请成功,则从空闲块链表上删除该节点,给相应线程 *  使用(删除后不管它了) * 4.释放时,将线程释放的内存块挂入待释放链表(加锁) * 5.空闲链表头部加入,头部取出,类似于栈,待释放链表只头部插入 * 6.为保证多线程安全,空闲块链表和待释放块链表各有一个互斥锁 */#include "MultiThread.h"#include <stdint.h>/*是否一次性申请一大块内存,然后切分成小block; *否则一小块一小块申请 *目前机器内存不是问题,默认使用第一种方式 */#define USE_LARGEMEMORYtypedef void* BLOCKID;//MEMLISTNODE地址,管理节点ptrclass CMemPool{public:    CMemPool()        :m_mutex_free(),m_mutex_tofree()    {#ifdef USE_LARGEMEMORY        m_pLargeBlock = NULL;#endif        m_uiBlockSize = 0;        m_uiBlockCount = 0;        m_uiBlockCountAlloc = 0;        m_uiBlockCountFree = 0;        m_pListNodeArray = NULL;        m_stFreeListHead.next = NULL;        m_stTofreeListHead.next = NULL;    }    virtual ~CMemPool()    {    }     /*     * 内存池初始化     * uiBlockSize为分配的内存块block大小byte,相同大小块     * uiBlockCount为分配的内存块数目     * */    bool Init(uint32_t uiBlockCount, uint32_t uiBlockSize)    {        if(uiBlockCount==0 || 0==uiBlockSize)            return false;#ifdef USE_LARGEMEMORY        m_pLargeBlock = malloc(uiBlockCount*uiBlockSize);        if(NULL == m_pLargeBlock)        {            perror("CMemPool::Init malloc large mem error 1\n");            _exit(-1);        }#endif        m_pListNodeArray = (MEMLISTNODE*)malloc(uiBlockCount*sizeof(MEMLISTNODE) );        if(NULL == m_pListNodeArray)        {            perror("CMemPool::Init malloc MEMLISTNODE array error 2\n");            _exit(-1);        }        memset(m_pListNodeArray,0,uiBlockCount*sizeof(MEMLISTNODE) );        if(uiBlockCount>0 && uiBlockSize>0)//check again        {            /*申请uiBlockCount个大小为uiBlockSize byte的内存块*/            for(uint32_t i=0; i<uiBlockCount; ++i)            {                void* pNewBlock = NULL; //raw mem ptr#ifndef USE_LARGEMEMORY                /*一个block一个block申请,基本不采用此方式*/                pNewBlock = malloc(uiBlockSize);                if(NULL == pNewBlock)                {                    perror("CMemPool::Init malloc failed 3\n");                    _exit(-2);                }#else                pNewBlock = (void*)((char*)m_pLargeBlock + i*uiBlockSize);#endif                /*新建一个链表节点,即block管理节点*/                MEMLISTNODE* pNewNode = &m_pListNodeArray[i];                pNewNode->pvMemBlock = pNewBlock;                pNewBlock->uiBlockSize = uiBlockSize;                /*加入到空闲块链表*/                pNewNode->next = m_stFreeListHead->next;                m_stFreeListHead->next = pNewNode;            }//end for        }//end if        m_uiBlockCount = uiBlockCount;        m_uiBlockSize = uiBlockSize;        return true;    }    void Exit()    {#ifdef USE_LARGEMEMORY        if(m_pLargeBlock)        {            free(m_pLargeBlock);            m_pLargeBlock = NULL;        }#endif        if(NULL != m_pListNodeArray)        {#ifndef USE_LARGEMEMORY            for(uint32_t i=0; i<m_uiBlockSize; ++i)            {                MEMLISTNODE* p = &m_pListNodeArray[i];                if(NULL != p->pvMemBlock)                {                    free(p->pvMemBlock);                    p->pvMemBlock = NULL;                }            }#endif            free(m_pListNodeArray);            m_pListNodeArray = NULL;        }    }    /*     * 从内存池中申请一个空闲block     * pBlock内存块block首地址,raw mem ptr     * uiBlockSize 内存块block大小     * 成功返回空闲块ID,管理节点地址,否则NULL     */    BLOCKID AllocBlock(void* &pBlock, uint32_t& uiBlockSize)    {        BLOCKID nBlockId = NULL;        MEMLISTNODE* pAvlNode = NULL;        MutexLockGuard freeLock(m_mutex_free);//生存期作用域恰为临界区        if(NULL == m_stFreeListHead.next)        {            if(NULL == m_stTofreeListHead.next)            {                return NULL;            }            MEMLISTNODE* ptofreeHead;            {                /*减小临界区*/                MutexLockGuard tofreeLock(m_mutex_tofree);                /*待释放链表实际头结点赋给空闲链表,自己为NULL*/                ptofreeHead = m_stTofreeListHead.next;                m_stTofreeListHead.next = NULL;            }            //这时待释放链表其他线程可以头部加入了            //交换            m_stFreeListHead.next = ptofreeHead;        }        pAvlNode = m_stFreeListHead.next;        if(pAvlNode)//申请成功        {            m_stFreeListHead.next = m_stFreeListHead.next.next;            m_uiBlockCountAlloc++;//已申请内存块个数            pBlock = pAvlNode->pvMemBlock;//raw            uiBlockSize = pAvlNode->uiBlockSize;            nBlockId = (BLOCKID)pAvlNode;        }        return nBlockId;    }    void FreeBlock(BLOCKID blockID)    {        MEMLISTNODE* pNode = (MEMLISTNODE*)blockID;        if(pNode)        {            MutexLockGuard tofreeLock(m_mutex_tofree);            pNode->next = m_stTofreeListHead.next;            m_stTofreeListHead.next = pNode;            m_uiBlockCountFree ++;//已释放内存块个数        }    }    uint32_t GetBlockSize()    {        return m_uiBlockSize;    }    uint32_t GetBlockCount()    {        return m_uiBlockCount;    }/*正在被线程使用的内存block个数*/    uint32_t GetBusyBlockCount()    {        return m_uiBlockCountAlloc - m_uiBlockCountFree;    }private:    /*block管理结构,管理数组,空闲链表、待释放链表节点*/    typedef struct _stMemListNode    {        void* pvMemBlock; //指向内存块block起始地址,raw mem ptr        uint32_t uiBlockSize; //内存块block大小        struct _stMemListNode* next; //next指针    }MEMLISTNODE,*MEMLIST;private:#ifdef USE_LARGEMEMORY    void* m_pLargeBlock; //一大块内存起始地址#endif    uint32_t m_uiBlockSize; //block内存块的大小(byte)    uint32_t m_uiBlockCount; //内存块数目    uint32_t m_uiBlockCountAlloc; //所有线程已申请的内存块数目    uint32_t m_uiBlockCountFree; //所有线程已释放的内存块数目    /*只有两个头结点需加锁*/    MEMLISTNODE m_stFreeListHead; //空闲块链表头结点    MutexLock m_mutex_free; //空闲链表互斥锁    MEMLISTNODE m_stTofreeListHead; //待释放链表头结点    MutexLock m_mutex_tofree; //待释放链表互斥锁private:    MEMLISTNODE* m_pListNodeArray; //链表节点数组,block集合管理节点数组,和block集合一一对应};#endif //_MEMPOOL_H

MultiThread.h请参考http://blog.csdn.net/nanjunxiao/article/details/8962831,是我自己的一个简单封装。

为了方便编辑实现都写到头文件了,默认为inline,使用时需剥离出实现到cpp文件。

1.内存池为多个相同大小的内存block集合,block大小和个数在初始化是设定。
 2.用两个链表管理内存池的block集合,一个为空闲块链表(可申请),另一个为
待释放块链表,这两个链表均为带头结点的单向非循环链表。实现时只提供空闲
 链表头和待释放链表头,具体链表节点为block管理节点(和block一一对应),每个
block管理节点内部包含block内存地址,大小和指向下一个管理节点的next指针。
3.申请时从空闲块链表上申请,若空闲块链表上已经没有空闲块,则将空闲块链表
和待释放块链表交换(加锁);若申请成功,则从空闲块链表上删除该节点,给相应线程
使用(删除后不管它了)
4.释放时,将线程释放的内存块挂入待释放链表(加锁)
5.空闲链表头部加入,头部取出,类似于栈,待释放链表只头部插入
6.为保证多线程安全,空闲块链表和待释放块链表各有一个互斥锁

双链表申请释放block管理算法如下图所示,底层为raw mem即虚拟内存,此时为一次申请一大块内存,如果第二种方式,

内存block是不连续的,此时注意释放问题。中间为内存块block管理节点数组,和block一一对应,最上面为两个链表头结点,链表节点为block管理节点。

此时可用为freehead->2->1,待释放为tofreehead->3->4。

申请时首先移除2,用完归还时加入到tofree,变为freehead->1,tofreehead->2->3->4。



原创粉丝点击