【网络编程/操作系统】Linux下对象池的简单实现

前言

一. 对象池是什么?

  大家应该对线程池,内存池等即便不知道原理,也有所耳闻了。同样的,对象池的大概思路和线程池,内存池一样。
  以线程池为例子说明,假定有一个服务端,一开始便分配了一定量的线程数(假设10个)。那么,当有10个客户端对服务端发起连接时。服务端便可直接将这10个客户端分配给事先准备的10个线程,而不需要临时创建10个线程,进而节省了大量的时间,同时也限制了一共可以处理的线程数,避免了资源过度占用。
  对象池也是如此,**缓存一些对象从而避免大量创建同一个类型的对象,同时限制了实例的个数。**对象池在游戏中就有常用的地方,如地图刷新时,就直接从对象池中直接拿出所有的怪物,而并非逐个创建怪物。

二.对象池应用场景

1. 对象类型体积较大。
2. 需要频繁创建和销毁对象,对象生命周期短。
3. 资源有限,不能一次性分配过多对象,所以设置对象池来限制对象的数量,同时增加对象的复用。

三.对象池图解

在这里插入图片描述
如上图中, 对象池的大小 = 空闲队列(freePool)的大小 + 工作队列(busyPool)的大小。 同理的,当工作对象使用完毕后,我们只需要调用其析构函数来进行释放。然后将该对象push回freePool队列中。

四.对象池简单实现

/* objectPool.h */
#ifndef OBJECT_POOL_H_
#define OBJECT_POOL_H_
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#include <memory>
#include <queue>
#include <vector>
#include <mutex>
/* 定义对象池模板类 */
template<typename T>
class ObjectPool
{
public:
    ObjectPool(size_t chuckSize = 10);
    virtual ~ObjectPool();
    void SetChuckSize(size_t chuckSize);
    
    /* 分配Object,并获取 */
    std::shared_ptr<T> AssignObject();
    /* 释放对象,并回到空闲对象队列 */
    void ReleaseObject(std::shared_ptr<T> obj);

private:
    /* 构造函数中调用 */
    void AllocateChunk();
    /* 析构函数中调用 */
    void DestroyPool();

private:
    /* 空闲对象池 */
    std::queue<std::shared_ptr<T> > _freeObjPool;
    /* 整体对象的大池 */
    std::queue<std::shared_ptr<T> > _allObjPool;
    size_t _chuckSize;
    std::mutex _queMutex;
};

template<typename T>
ObjectPool<T>::ObjectPool(size_t chuckSize):_chuckSize(chuckSize){
    if(_chuckSize < 0){
        assert(false);
        return;
    }
    for (size_t i = 0; i < _chuckSize; i++)
    {
       /* 创建新对象,并进入空闲对象队列 */
       AllocateChunk();
    }
}

template<typename T>
ObjectPool<T>::~ObjectPool(){
    DestroyPool();
}

template<typename T>
void ObjectPool<T>::SetChuckSize(size_t chuckSize){
    if(chuckSize > _chuckSize){
        for (size_t i = 0; i < chuckSize - _chuckSize; i++)
        {
            AllocateChunk();
        }
    }else
    {
        return;
    }
}

template<typename T>
void ObjectPool<T>::AllocateChunk(){
    std::shared_ptr<T> Obj(new T());
    _queMutex.lock();
    _freeObjPool.push(Obj);
    _allObjPool.push(Obj);
    _queMutex.unlock();
}

template<typename T>
std::shared_ptr<T> ObjectPool<T>::AssignObject(){
    /* 若空闲队列为空,则另外分配一个对象 */
    if(_freeObjPool.empty()){
        AllocateChunk();
    }
    if(_freeObjPool.empty()){
        assert(false);
        return nullptr;
    }
    /* 从空闲队列的头部取出一个obj */
    std::shared_ptr<T> assignObj = _freeObjPool.front();
    /* 出队 */
    _queMutex.lock();
    _freeObjPool.pop();
    _queMutex.unlock();
    return assignObj;
}

template<typename T>
void ObjectPool<T>::ReleaseObject(std::shared_ptr<T> Obj){
    if(Obj == nullptr){
        assert(false);
        return;
    }
    Obj->~T();
    /* 加入回空闲对象队列 */
    _queMutex.lock();
    _freeObjPool.push(Obj);
    _queMutex.unlock();
}

template<typename T>
void ObjectPool<T>::DestroyPool(){
    if(_allObjPool.empty()){
        assert(false);
        return;
    }
    _queMutex.lock();
    for (size_t i = 0; i < _chuckSize; i++)
    {
        std::shared_ptr<T> tmpObj = _allObjPool.front();
        _allObjPool.pop();
    }
    _queMutex.unlock();
}
#endif
/* main.cpp */
#include "objectPool.hpp"
class Test
{
	public:
		void PrintAddr()
		{
			printf( "address: %p\n", this );
		}
};
int main()
{
    /* 初始化Test类型的对象池,size为2 */
	ObjectPool< Test > TestPool( 2 );
 
	/* 从对象池中分配obj */
	std::shared_ptr<Test> pTest1 = TestPool.AssignObject();
	std::shared_ptr<Test> pTest2 = TestPool.AssignObject();
	pTest1->PrintAddr();
	pTest2->PrintAddr();
	/* 回到对象池中 */
	TestPool.ReleaseObject( pTest1 );
	TestPool.ReleaseObject( pTest2 );
 
	/* 从对象池中分配obj */
	pTest1 = TestPool.AssignObject();
	pTest2 = TestPool.AssignObject();
	pTest1->PrintAddr();
	pTest2->PrintAddr();
	/* 回到对象池中 */
	TestPool.ReleaseObject( pTest1 );
	TestPool.ReleaseObject( pTest2 );
	return 0;
}

命令行中执行如下命令编译:

g++ main.cpp -o test -std=c++11
./test

我们可以看到对象池建立成功了,从打印出来的pTest1和pTest2的地址看得出对象是多次复用的,迟点将队列换成无锁队列。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值