今天放上 对象池的实现
思路类似于之前的内存池
PS
2013.3.6修改:
去掉了索引树以及搜索功能
因为该功能可以通过TTree来实现,结点分配可以通过new,也可以通过内存池
封装在对象池中反而显得不灵活
索引功能的实现在下一篇文章中做简单介绍
2013.6.26修改:
由于容器、迭代器的修改,做相关调用的调整
和之前内存池的区别:
1、除了使用列表used和空闲列表free之外,另外提供了一个待赋值列表assign
增加assign做用是: 对某个分配出来的结点的赋值操作 和 对使用列表的遍历操作
可以在不同的线程同时执行而不用加锁
申请一个结点(Malloc)后,对结点的赋值操作,在很多情况下可能是异步的
而赋值未完成的结点,通常不希望被遍历处理到或者不希望被Find搜索出来
当开启使用assign列表时,Malloc出来的结点默认是被放入assign列表而不是使用列表used
当赋值完成时需要调用Use()将其放入使用列表
在使用列表中的结点需要中途修改其值时,若不希望在被修改的时候被其他线程遍历或查找
需要调用Assign()将其放回待赋值的列表assign
2、提供遍历的功能
BeginList()表示开始遍历,GetNextUsedObj()获取下一个结点
这两个函数都有加锁,保证遍历的线程安全
但是有一个问题,若GetNextUsedObj()返回出来的结点,在另一个线程中同时被操作了,这个是没有加锁的
若有需要,调用者需要自己另行加锁保证每一个对象的线程安全
若是待遍历的下一个结点,被另一个线程同时操作了(Free或者Assign)
那么(Free或者Assign)会自行将m_pNextLinker后移,保证遍历的正确性
3、因为对象池,其所管理的是同种对象
因此也就不再有元内存块的概念,每个对象所占内存大小是固定的
因此也不再需要内存池中的CMemLinker来管理结点
在对象池中是直接由双链表跟树来管理结点的
详细代码
TObjectAllocator.h
#ifndef _TObjectAllocator_h_
#define _TObjectAllocator_h_
#include <windows.h>
#include "TBDLinkList.h"
#include "tool.h"
//对象池的分配子
template <class T>
class TObjectAllocator
{
public:
TObjectAllocator();
~TObjectAllocator();
//申请一块连续的内存,在这块内存上创建对象管理结点
//dwObjCount: 容纳的对象个数
//list: 这些被分配出来的对象需要被放入的链表管理器
public:
bool Init(DWORD dwObjCount, TBDLinkList<T> &list);
//释放Init申请的连续的内存
public:
void Release();
//判断一个T对象是否是由本分配子分配管理的
//即计算p的地址值是否在本分配子申请的内存地址区间内
//是则返回T对应的TBDLinker
//否则返回NULL
public:
TBDLinker<T> *GetObjLinker(const T *p);
//由于分配子用AVL树来管理
//这里提供2个比较函数函数
//以及获取关键字的函数
public:
char *GetKey();
bool operator==(const char *k);
bool operator>(const char *k);
private:
TBDLinker<T> *m_pHead; //对象链表头指针
char *m_pStartAddr; //该分配子申请的m_pHead的起始地址的数值
char *m_pEndAddr; //该分配子申请的m_pHead的结束地址的数值
};
#include "TObjectAllocator.hpp"
#endif
TObjectAllocator.hpp
#ifndef _TObjectAllocator_hpp_
#define _TObjectAllocator_hpp_
template <class T>
TObjectAllocator<T>::TObjectAllocator()
{
m_pHead = NULL;
m_pStartAddr = NULL;
m_pEndAddr = NULL;
}
template <class T>
TObjectAllocator<T>::~TObjectAllocator()
{
Release();
}
template <class T>
bool TObjectAllocator<T>::Init(DWORD dwObjCount, TBDLinkList<T> &list)
{
if (NULL != m_pHead)
{
//该对象现已有所管理的内存,不可以初始化
return false;
}
else if (0 == dwObjCount)
{
//初始化参数不正确
return false;
}
else
{
//分配内存
m_pHead = new TBDLinker<T>[dwObjCount];
if (NULL == m_pHead)
{
return false;
}
m_pStartAddr = (char *)m_pHead;
m_pEndAddr = (char *)m_pHead + sizeof(TBDLinker<T>) * dwObjCount - 1;
//初始化管理结点,放入管理容器
for (DWORD i = 0; i < dwObjCount; i++)
{
m_pHead[i].Init();
list.PushTail(&(m_pHead[i]));
}
return true;
}
}
template <class T>
void TObjectAllocator<T>::Release()
{
if (NULL != m_pHead)
{
delete[] m_pHead;
m_pHead = NULL;
m_pStartAddr = NULL;
m_pEndAddr = NULL;
}
}
template <class T>
TBDLinker<T> *TObjectAllocator<T>::GetObjLinker(const T *p)
{
if (NULL != p)
{
TBDLinker<T> *pLinker = ContainerOf(p, TBDLinker<T>, m_Value);
char *pAddr = (char *)pLinker;
if (m_pStartAddr <= pAddr && pAddr <= m_pEndAddr)
{
if ( 0 == (pAddr - m_pStartAddr) % sizeof(TBDLinker<T>) )
{
return pLinker;
}
}
}
return NULL;
}
template <class T>
char *TObjectAllocator<T>::GetKey()
{
return m_pStartAddr;
}
template <class T>
bool TObjectAllocator<T>::operator==(const char *k)
{
if (m_pStartAddr <= k && k <= m_pEndAddr)
{
return true;
}
else
{
return false;
}
}
template <class T>
bool TObjectAllocator<T>::operator>(const char *k)
{
if (m_pStartAddr > k)
{
return true;
}
else
{
return false;
}
}
#endif
TObjectPool.h
#ifndef _TObjectPool_h_
#define _TObjectPool_h_
#include <windows.h>
#include "TBDLinkList.h"
#include "TTree.h"
#include "TObjectAllocator.h"
#include "CLock.h"
#include "tool.h"
enum ObjPoolFlag
{
enum_EnableAssign = 0, //是否开启Assign列表
enum_DisableAssign,
};
//对象池
//
//对象池有3个状态的队列
//可以正常使用的对象列表:m_Used
//分配完毕,但还不能直接使用,正在等待逻辑对其赋值的对象列表:m_Assign
//空闲对象列表:m_Free
//增加m_Assign做用是使 对某个分配出来的结点的赋值操作 和 对使用列表的遍历操作
//可以在不同的线程同时执行而不用加锁
//对 结点的赋值操作 在很多情况下可能是异步的
//而赋值未完成的结点 通常不希望被遍历处理 或者不希望被Find搜索出来
template <class T>
class TObjectPool
{
public:
TObjectPool();
~TObjectPool();
//初始化函数
//dwFirstObjCount: 对象池初始分配对象个数
// 不允许为0
//dwAddObjCount: 对象池对象不够时,新增分配对象个数,
// 允许传0,表示对象不够时不开辟新内存,返回空
//dwLock: 设置是否使用临界区
// 初始默认为Enable,即使用临界区
//dwAssignList: 设置是否使用Assign列表
// 初始默认为Disable,即不使用Assign列表
public:
bool Init(DWORD dwFirstObjCount,
DWORD dwAddObjCount,
ContainerFlag dwLock = enum_EnableLock,
ObjPoolFlag dwAssignList = enum_DisableAssign);
//释放对象池的所有分配子
public:
void Release();
//对象池对象不够时,增加分配子,开辟新内存
private:
bool AddObject(DWORD dwAddCount);
//从空闲列表Free得到一个对象结点
//如果有使用Assign,放入等待赋值列表Assign
//否则,放入使用列表Used
//返回获取到的结点所管理的那个对象指针,当没有空闲结点时返回NULL
public:
T *Malloc();
//将指定对象从使用列表Used或者等待赋值列表Assign放入空闲列表Free
public:
bool Free(const T *pObj);
//当且仅当使用列表Assign时
//将指定结点从等待赋值列表Assign放入使用列表Used
public:
bool Use(const T *pObj);
//当且仅当使用列表Assign时
//将指定结点从使用列表Used放回等待赋值列表Assign
public:
bool Assign(const T *pObj);
//给使用列表Used注册迭代器
//遍历,获取使用列表Used中的一个T对象
//这两个函数已加锁
//在多线程环境下
//若GetNextUsedObj返回之后的T对象被另一个线程进行了移动(Free或者Assign)
//暂时需要调用者自行判断或加锁
//若GetNextUsedObj返回之后下一个待遍历的结点被另一个线程进行了移动
//m_pNextLinker会自行继续指向下一个,不会出现遍历错误
public:
void RegisterForUsed(TIterator<T>& iterator);
void BeginUsedList(TIterator<T>& iterator);
T *GetNextUsedObj(TIterator<T>& iterator);
//获取当前各个列表使用情况
public:
DWORD GetUsedListLen();
DWORD GetAssignListLen();
DWORD GetFreeListLen();
private:
TBDLinkList<T> m_Used;//可以正常使用的对象列表
TBDLinkList<T> m_Assign;//分配完毕,但还不能直接使用,正在等待赋值的对象列表
TBDLinkList<T> m_Free;//空闲对象列表
TTree<char *, TObjectAllocator<T>> m_MemAllocList;//对象池分配子管理链表
DWORD m_dwAddObjCount;
ObjPoolFlag m_dwAssignList; //Assign列表使用开关
CLock m_csLock; //临界区,保证池操作的线程安全
ContainerFlag m_dwLock; //是否使用临界区进行加锁
};
#include "TObjectPool.hpp"
#endif
TObjectPool.hpp
#ifndef _TObjectPool_hpp_
#define _TObjectPool_hpp_
template <class T>
TObjectPool<T>::TObjectPool()
{
m_Used.Init(enum_DisableLock);
m_Assign.Init(enum_DisableLock);
m_Free.Init(enum_DisableLock);
m_MemAllocList.Init(enum_DisableLock);
m_dwAddObjCount = 0;
m_dwAssignList = enum_DisableAssign;
m_dwLock = enum_EnableLock;
}
template <class T>
TObjectPool<T>::~TObjectPool()
{
Release();
}
template <class T>
bool TObjectPool<T>::Init(DWORD dwFirstObjCount,
DWORD dwAddObjCount,
ContainerFlag dwLock,
ObjPoolFlag dwAssignList)
{
if (0 == dwFirstObjCount)
{
//初始化参数不正确
return false;
}
else
{
Release();
m_dwAddObjCount = dwAddObjCount;
m_dwLock = dwLock;
m_dwAssignList = dwAssignList;
//申请分配子,开辟第一块内存
return AddObject(dwFirstObjCount);
}
}
template <class T>
void TObjectPool<T>::Release()
{
m_Used.Init(enum_DisableLock);
m_Assign.Init(enum_DisableLock);
m_Free.Init(enum_DisableLock);
TLeaf<char *, TObjectAllocator<T>> *pLeaf = m_MemAllocList.RemoveHead();
while (NULL != pLeaf)
{
delete pLeaf;
pLeaf = m_MemAllocList.RemoveHead();
}
m_MemAllocList.Init(enum_DisableLock);
m_dwAddObjCount = 0;
m_dwAssignList = enum_DisableAssign;
m_dwLock = enum_EnableLock;
}
template <class T>
bool TObjectPool<T>::AddObject(DWORD dwAddCount)
{
if (0 == dwAddCount)
{
return false;
}
else
{
TLeaf<char *, TObjectAllocator<T>> *pAllocLinker = new TLeaf<char *, TObjectAllocator<T>>;
if (NULL == pAllocLinker)
{
return false;
}
pAllocLinker->Init();
if (!pAllocLinker->m_Value.Init(dwAddCount, m_Free))
{
delete pAllocLinker;
return false;
}
pAllocLinker->m_Key = pAllocLinker->m_Value.GetKey();
m_MemAllocList.Insert(pAllocLinker);
return true;
}
}
template <class T>
T *TObjectPool<T>::Malloc()
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
TBDLinker<T> *pLinker = m_Free.PopHead();
if (NULL == pLinker)
{
if (AddObject(m_dwAddObjCount))
{
pLinker = m_Free.PopHead();
}
}
if (NULL == pLinker)
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return NULL;
}
else
{
if (enum_EnableAssign == m_dwAssignList)
{
m_Assign.PushTail(pLinker);
}
else
{
m_Used.PushTail(pLinker);
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return &(pLinker->m_Value);
}
}
template <class T>
bool TObjectPool<T>::Free(const T *pObj)
{
if (NULL != pObj)
{
bool bRes = false;
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
char *pBuffAddr = (char *)pObj;
TLeaf<char *, TObjectAllocator<T>> *pAllocLinker = m_MemAllocList.Find(pBuffAddr);
if (NULL != pAllocLinker)
{
TBDLinker<T> *pLinker = pAllocLinker->m_Value.GetObjLinker(pObj);
if (NULL != pLinker)
{
if (&m_Used == pLinker->m_pLinkList)
{
m_Used.Remove(pLinker);
m_Free.PushTail(pLinker);
bRes = true;
}
else if (&m_Assign == pLinker->m_pLinkList)
{
m_Assign.Remove(pLinker);
m_Free.PushTail(pLinker);
bRes = true;
}
}
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return bRes;
}
return false;
}
template <class T>
bool TObjectPool<T>::Use(const T *pObj)
{
if (NULL != pObj && enum_EnableAssign == m_dwAssignList)
{
bool bRes = false;
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
char *pBuffAddr = (char *)pObj;
TLeaf<char *, TObjectAllocator<T>> *pAllocLinker = m_MemAllocList.Find(pBuffAddr);
if (NULL != pAllocLinker)
{
TBDLinker<T> *pLinker = pAllocLinker->m_Value.GetObjLinker(pObj);
if (NULL != pLinker)
{
if (&m_Assign == pLinker->m_pLinkList)
{
m_Assign.Remove(pLinker);
m_Used.PushTail(pLinker);
bRes = true;
}
}
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return bRes;
}
return false;
}
template <class T>
bool TObjectPool<T>::Assign(const T *pObj)
{
if (NULL != pObj && enum_EnableAssign == m_dwAssignList)
{
bool bRes = false;
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
char *pBuffAddr = (char *)pObj;
TLeaf<char *, TObjectAllocator<T>> *pAllocLinker = m_MemAllocList.Find(pBuffAddr);
if (NULL != pAllocLinker)
{
TBDLinker<T> *pLinker = pAllocLinker->m_Value.GetObjLinker(pObj);
if (NULL != pLinker)
{
if (&m_Used == pLinker->m_pLinkList)
{
m_Used.Remove(pLinker);
m_Assign.PushTail(pLinker);
bRes = true;
}
}
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return bRes;
}
return false;
}
template <class T>
void TObjectPool<T>::RegisterForUsed(TIterator<T>& iterator)
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
iterator.Register(m_Used);
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
}
template <class T>
void TObjectPool<T>::BeginUsedList(TIterator<T>& iterator)
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
iterator.BeginList();
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
}
template <class T>
T *TObjectPool<T>::GetNextUsedObj(TIterator<T>& iterator)
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
T *pNext = iterator.GetNext();
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return pNext;
}
template <class T>
DWORD TObjectPool<T>::GetUsedListLen()
{
return m_Used.GetLen();
}
template <class T>
DWORD TObjectPool<T>::GetAssignListLen()
{
return m_Assign.GetLen();
}
template <class T>
DWORD TObjectPool<T>::GetFreeListLen()
{
return m_Free.GetLen();
}
#endif