多线程内存池实现代码-双链表
来源:互联网 发布: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。
- 多线程内存池实现代码-双链表
- 多线程内存池实现
- 多线程内存池实现
- C++实现多线程全局内存池
- BCB多线程实现代码
- 多线程实现(代码)
- 内存池的实现以及代码详解
- 代码实现内存溢出
- C++实现内存池MemoryPool 包含单线程和多线程
- C++实现多线程对象内存池带垃圾回收机制
- C++实现多线程全局内存池(性能优化)
- 多线程-多线程方式1的代码实现
- 学习多线程代码遇到内存泄露
- 实现多线程下载的代码
- c#实现多线程代码例子
- c#实现多线程代码例子
- c#实现多线程代码例子
- java实现socket多线程代码
- Response.Redirect ,Server.Transfer ,Server.Execute, 的区别(比较)
- iOS学习--NSCalendar
- Linux Shell 通配符、元字符、转义符使用实例介绍
- Ubuntu 12.10安装google chrome浏览器
- 算法复杂度总结!
- 多线程内存池实现代码-双链表
- HDU——3602 2012
- oracle 隨機取數據
- struts 表单乱码
- C#常用文件操作
- 使用spring配置RMI
- Android资源目录---assets与res/raw区别
- jsp之监听器
- zencart忘记后台密码的解决办法