KBEngine中的对象池

编程中常常看到将许多东西放在资源池中,在使用的时候可以提高效率。看起来和实现一个缓存类型,虽然原理简单,但是徒手写有总觉得缺点什么,所以在此总结一下

1.对象池

template< typename T, typename THREADMUTEX = KBEngine::thread::ThreadMutexNull >
class ObjectPool
{
public:
    typedef std::list<T*> OBJECTS;

    ObjectPool(std::string name):
        objects_(),
        max_(OBJECT_POOL_INIT_MAX_SIZE),
        isDestroyed_(false),
        pMutex_(new THREADMUTEX()),
        name_(name),
        total_allocs_(0),
        obj_count_(0),
        lastReducingCheckTime_(timestamp())
    {
    }

    ObjectPool(std::string name, unsigned int preAssignVal, size_t max):
        objects_(),
        max_((max == 0 ? 1 : max)),
        isDestroyed_(false),
        pMutex_(new THREADMUTEX()),
        name_(name),
        total_allocs_(0),
        obj_count_(0),
        lastReducingCheckTime_(timestamp())
    {
    }

    ~ObjectPool()
    {
        destroy();
        SAFE_RELEASE(pMutex_);
    }   

    void destroy()
    {
        pMutex_->lockMutex();

        isDestroyed_ = true;

        typename OBJECTS::iterator iter = objects_.begin();
        for(; iter!=objects_.end(); ++iter)
        {
            (*iter)->isEnabledPoolObject(false);
            if(!(*iter)->destructorPoolObject())
            {
                delete (*iter);
            }
        }

        objects_.clear();
        obj_count_ = 0;
        pMutex_->unlockMutex();
    }

    const OBJECTS& objects(void) const
    {
        return objects_;
    }

    void pMutex(KBEngine::thread::ThreadMutexNull* pMutex)
    {
        SAFE_RELEASE(pMutex_);
        pMutex_ = pMutex;
    }

    KBEngine::thread::ThreadMutexNull* pMutex()
    {
        return pMutex_;
    }

    void assignObjs(unsigned int preAssignVal = OBJECT_POOL_INIT_SIZE)
    {
        for(unsigned int i=0; i<preAssignVal; ++i)
        {
            T* t = new T();
            t->isEnabledPoolObject(false);
            objects_.push_back(t);
            ++total_allocs_;
            ++obj_count_;
        }
    }

    /**
        强制创建一个指定类型的对象。 如果缓冲里已经创建则返回现有的,否则
        创建一个新的, 这个对象必须是继承自T的。
    */
    template<typename T1>
    T* createObject(void)
    {
        pMutex_->lockMutex();

        while(true)
        {
            if(obj_count_ > 0)
            {
                T* t = static_cast<T1*>(*objects_.begin());
                objects_.pop_front();
                --obj_count_;
                t->onEabledPoolObject();
                t->isEnabledPoolObject(true);
                pMutex_->unlockMutex();
                return t;
            }

            assignObjs();
        }

        pMutex_->unlockMutex();

        return NULL;
    }

    /**
        创建一个对象。 如果缓冲里已经创建则返回现有的,否则
        创建一个新的。
    */
    T* createObject(void)
    {
        pMutex_->lockMutex();

        while(true)
        {
            if(obj_count_ > 0)
            {
                T* t = static_cast<T*>(*objects_.begin());
                objects_.pop_front();
                --obj_count_;
                t->onEabledPoolObject();
                t->isEnabledPoolObject(true);
                pMutex_->unlockMutex();
                return t;
            }

            assignObjs();
        }

        pMutex_->unlockMutex();

        return NULL;
    }

    /**
        回收一个对象
    */
    void reclaimObject(T* obj)
    {
        pMutex_->lockMutex();
        reclaimObject_(obj);
        pMutex_->unlockMutex();
    }

    /**
        回收一个对象容器
    */
    void reclaimObject(std::list<T*>& objs)
    {
        pMutex_->lockMutex();

        typename std::list< T* >::iterator iter = objs.begin();
        for(; iter != objs.end(); ++iter)
        {
            reclaimObject_((*iter));
        }

        objs.clear();

        pMutex_->unlockMutex();
    }

    /**
        回收一个对象容器
    */
    void reclaimObject(std::vector< T* >& objs)
    {
        pMutex_->lockMutex();

        typename std::vector< T* >::iterator iter = objs.begin();
        for(; iter != objs.end(); ++iter)
        {
            reclaimObject_((*iter));
        }

        objs.clear();

        pMutex_->unlockMutex();
    }

    /**
        回收一个对象容器
    */
    void reclaimObject(std::queue<T*>& objs)
    {
        pMutex_->lockMutex();

        while(!objs.empty())
        {
            T* t = objs.front();
            objs.pop();
            reclaimObject_(t);
        }

        pMutex_->unlockMutex();
    }

    size_t size(void) const { return obj_count_; }

    std::string c_str()
    {
        char buf[1024];

        pMutex_->lockMutex();

        sprintf(buf, "ObjectPool::c_str(): name=%s, objs=%d/%d, isDestroyed=%s.\n",
            name_.c_str(), (int)obj_count_, (int)max_, (isDestroyed() ? "true" : "false"));

        pMutex_->unlockMutex();

        return buf;
    }

    size_t max() const { return max_; }
    size_t totalAllocs() const { return total_allocs_; }

    bool isDestroyed() const { return isDestroyed_; }

protected:
    /**
        回收一个对象
    */
    void reclaimObject_(T* obj)
    {
        if(obj != NULL)
        {
            // 先重置状态
            obj->onReclaimObject();
            obj->isEnabledPoolObject(false);

            if(size() >= max_ || isDestroyed_)
            {
                delete obj;
                --total_allocs_;
            }
            else
            {
                objects_.push_back(obj);
                ++obj_count_;
            }
        }

        uint64 now_timestamp = timestamp();

        if (obj_count_ <= OBJECT_POOL_INIT_SIZE)
        {
            // 小于等于则刷新检查时间
            lastReducingCheckTime_ = now_timestamp;
        }
        else if (now_timestamp - lastReducingCheckTime_ > OBJECT_POOL_REDUCING_TIME_OUT)
        {
            // 长时间大于OBJECT_POOL_INIT_SIZE未使用的对象则开始做清理工作
            size_t reducing = std::min(objects_.size(), std::min((size_t)OBJECT_POOL_INIT_SIZE, (size_t)(obj_count_ - OBJECT_POOL_INIT_SIZE)));

            //printf("ObjectPool::reclaimObject_(): start reducing..., name=%s, currsize=%d, OBJECT_POOL_INIT_SIZE=%d\n",
            //  name_.c_str(), (int)objects_.size(), OBJECT_POOL_INIT_SIZE);

            while (reducing-- > 0)
            {
                T* t = static_cast<T*>(*objects_.begin());
                objects_.pop_front();
                delete t;

                --obj_count_;
            }

            //printf("ObjectPool::reclaimObject_(): reducing over, name=%s, currsize=%d\n",
            //  name_.c_str(), (int)objects_.size());

            lastReducingCheckTime_ = now_timestamp;
        }
    }

protected:
    OBJECTS objects_;

    size_t max_;

    bool isDestroyed_;

    // 一些原因导致锁还是有必要的
    // 例如:dbmgr任务线程中输出log,cellapp中加载navmesh后的线程回调导致的log输出
    THREADMUTEX* pMutex_;

    std::string name_;

    size_t total_allocs_;

    // Linux环境中,list.size()使用的是std::distance(begin(), end())方式来获得
    // 会对性能有影响,这里我们自己对size做一个记录
    size_t obj_count_;

    // 最后一次瘦身检查时间
    // 如果长达OBJECT_POOL_REDUCING_TIME_OUT大于OBJECT_POOL_INIT_SIZE,则最多瘦身OBJECT_POOL_INIT_SIZE个
    uint64 lastReducingCheckTime_;
};

/*
    池对象, 所有使用池的对象必须实现回收功能。
*/
class PoolObject
{
public:
    PoolObject() :
        isEnabledPoolObject_(false)
    {

    }

    virtual ~PoolObject(){}
    virtual void onReclaimObject() = 0;
    virtual void onEabledPoolObject() {
    }

    virtual size_t getPoolObjectBytes()
    {
        return 0;
    }

    /**
        池对象被析构前的通知
        某些对象可以在此做一些工作
    */
    virtual bool destructorPoolObject()
    {
        return false;
    }

    bool isEnabledPoolObject() const
    {
        return isEnabledPoolObject_;
    }

    void isEnabledPoolObject(bool v)
    {
        isEnabledPoolObject_ = v;
    }

protected:

    // 池对象是否处于激活(从池中已经取出)状态
    bool isEnabledPoolObject_;
};

template< typename T >
class SmartObjectPool : public ObjectPool<T>
{
public:
};

template< typename T >
class SmartPoolObject
{
public:
    SmartPoolObject(T* pPoolObject, ObjectPool<T>& objectPool):
      pPoolObject_(pPoolObject),
      objectPool_(objectPool)
    {
    }

    ~SmartPoolObject()
    {
        onReclaimObject();
    }

    void onReclaimObject()
    {
        if(pPoolObject_ != NULL)
        {
            objectPool_.reclaimObject(pPoolObject_);
            pPoolObject_ = NULL;
        }
    }

    T* get()
    {
        return pPoolObject_;
    }

    T* operator->()
    {
        return pPoolObject_;
    }

    T& operator*()
    {
        return *pPoolObject_;
    }

private:
    T* pPoolObject_;
    ObjectPool<T>& objectPool_;
};

#define NEW_POOL_OBJECT(TYPE) TYPE::createPoolObject();

2.进程池和线程池

3.内存池

4.数据库连接池

etc

原文地址:https://www.cnblogs.com/dingbin1995/p/8608327.html

时间: 2024-10-09 23:29:32

KBEngine中的对象池的相关文章

GameObjectPool——Unity中的对象池

这里介绍一种对象池的写法.它的优点在于无论取出还是插入游戏物体都是常数量时间. using UnityEngine; using System.Collections; using System.Collections.Generic; //对象池 public class GameObjectPool : MonoSingleton<GameObjectPool> { /// <summary>可能存放多个种类的对象,每个种类有多个对象 </summary> priv

关于tomcat中Servlet对象池

Servlet在不实现SingleThreadModel的情况下运行时是以单个实例模式,如下图,这种情况下,Wrapper容器只会通过反射实例化一个Servlet对象,对应此Servlet的所有客户端请求都会共用此Servlet对象,而对于多个客户端请求tomcat会使用多线程处理,所以应该保证此Servlet对象的线程安全,多个线程不管执行顺序如何都能保证执行结果的正确性.例如刚做web应用开发时可能会犯的一个错误:在某个Servlet中使用成员变量累加去统计访问次数,这就存在线程安全问题.

对象池的设计

对象池的设计及其实现 对象池概述: 对象池模型创建并拥有固定数量的对象,当程序需要一个新的对象时,如果对象池中有空闲对象,则立即返回,否则才创建新的该类对象.当一个对象不再被使用时,其应该应该将其放回对象池,以便后来的程序使用.由于系统资源有限,一个对象池模型应该指定其可容纳的最大对象数量.当达到该数量时,如果仍然有对象创建请求,则抛出异常或者阻塞当前调用线程,直到一个对象被放回对象池中. 对象池模型适用的场景: (1)需要使用大量对象 (2)这些对象的实例化开销比较大且生存期比较短 对象池优势

对象池的设计及其实现

对象池概述: 对象池模型创建并拥有固定数量的对象,当程序需要一个新的对象时,如果对象池中有空闲对象,则立即返回,否则才创建新的该类对象.当一个对象不再被使用时,其应该应该将其放回对象池,以便后来的程序使用.由于系统资源有限,一个对象池模型应该指定其可容纳的最大对象数量.当达到该数量时,如果仍然有对象创建请求,则抛出异常或者阻塞当前调用线程,直到一个对象被放回对象池中. 对象池模型适用的场景: (1)需要使用大量对象 (2)这些对象的实例化开销比较大且生存期比较短 对象池优势: 一个对象池可以在可

Unity3D 基于预设(Prefab)的泛型对象池实现

背景 在研究Inventory Pro插件的时候,发现老外实现的一个泛型对象池,觉得设计的小巧实用,不敢私藏,特此共享出来. 以前也看过很多博友关于对象池的总结分享,但是世界这么大,这么复杂到底什么样的对象池才是好的呢,我们发现通用的对象池未必适应所有的环境,比如基于UI的局部(从某个Scene,到某个Dialog)对象池,范围不同,需要的对象池就有不同的要求.本文就是介绍一种基于预设(Prefab)的局部UI对象池. 通用信息提示窗口的实现http://www.manew.com/thread

什么是对象池

COM+ 对象池服务可以减少从头创建每个对象的系统开销. 在激活对象时,它从池中提取.在停用对象时,它放回池中,等待下一个请求. 对象池使您能够控制所使用的连接数量,与连接池相反,连接池用来控制达到的最大数量.下面是对象池和连接池之间的重要区别: 创建 使用连接池时,创建在同一线程上进行,因此如果池中没有连接,则代表您创建连接.采用对象池时,池可以决定创建新对象.但是,如果已经达到最大数量,它会给您下一个可用的对象.当需要花费较长时间来创建对象时,这的确是一个重要的行为.但不要长期使用这种方法来

c++实现游戏开发中常用的对象池(含源码)

c++实现游戏开发中常用的对象池(含源码) little_stupid_child2017-01-06上传 对象池的五要素: 1.对象集合 2.未使用对象索引集合 3.已使用对象索引集合 4.当前使用量 5.最大使用量 http://download.csdn.net/download/little_stupid_child/9730912

Unity3D中对象池的实现

在Unity中常常会遇到需要重复创建,销毁某些物体的情况,比如fps类游戏中的子弹,rpg类游戏中的小怪等等,如果直接使用Instantiate和Destroy的话,会浪费系统的资源,而使用对象池则能够节省下这些浪费. 这里使用一个重复利用子弹的进行发射的简单场景来演示对象池. 首先需要一个在场景中创建一个Cube,充当子弹. 然后在Assets目录下创建Resources文件夹,在Cube上添加上刚体,取消重力后,将Cube拖入Resources文件夹内作为一个预设,在场景中删除这个Cube.

《Unity3D》通过对象池模式,管理场景中的元素

池管理类有啥用? 在游戏场景中,我们有时候会需要复用一些游戏物体,比如常见的子弹.子弹碰撞类,某些情况下,怪物也可以使用池管理,UI部分比如:血条.文字等等 这些元素共同的特性是:存在固定生命周期,使用比较频繁,场景中大量使用. 所以,我们就通过池管理思路,在游戏初始化的时候,生成一个初始的池,存放我们要复用的元素, 当要用到时,从池中取出:生命周期结束,放回到池中. 代码 这个池的参数有两个:1池中存放的元素 2 池的初始容量(如果池不够了,则会按照这个容量进行扩展) 代码如下 using S