您的位置:首页 > 编程语言

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

2013-05-24 16:19 239 查看
一下代码为一个简单的多线程内存池实现,内存池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_LARGEMEMORY

typedef void* BLOCKID;//MEMLISTNODE地址,管理节点ptr

class 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请参考/article/2365575.html,是我自己的一个简单封装。

为了方便编辑实现都写到头文件了,默认为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。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: