自己的底层代码库(六)——对象池

今天放上 对象池的实现

思路类似于之前的内存池


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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值