多线程内存池实现代码-双链表
2013-05-24 16:19
239 查看
一下代码为一个简单的多线程内存池实现,内存池block块大小固定,采用双链表实现block申请、释放管理。
比较简单,参考注释和readme基本可以看懂,不多介绍了。
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。
比较简单,参考注释和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。
相关文章推荐
- 线性表之单链表 图解和代码实现
- Java面试题-实现复杂链表的复制代码分享
- 单链表实现代码
- 单端链表、双端链表、双向链表的代码实现
- 探究数据结构之链表Java代码实现(二)
- 面试题5:从尾到头打印链表的c++代码实现
- 如何判断链表有没有环,环的大小?环的切入点在哪里以及链表的长度(分别用javascrip和Java代码实现)
- java双向循环链表的实现代码
- Java实现代码-链表
- C++ 构造双向链表的实现代码
- 【自编小代码】用链表实现对键盘的输入进行排序
- 用一段代码实现一个链表倒序(C++实现)
- 单链表反转python实现代码示例
- 探究数据结构之链表Java代码实现(一)
- 双向链表代码实现-C语言
- javascript写的一个链表实现代码
- java实现链表结构详细代码
- C# 泛型实现链表、代码重用
- 链表数据结构图解 和 代码实现
- (Java代码实现)单链表有环的一系列问题