Boost logo

Boost Users :

Subject: [Boost-users] My homemade object pool
From: 饭桶 (arthur.wang2_at_[hidden])
Date: 2012-03-27 11:51:36


Hi all
Here is my objectpool implemention which inspired by boost pool.
Which have following features.
Features:
1.Allocate an object from pre-allocate memory, when free an object just put
it back to pool.
2.Call object's contructor at pool memory allocating or get object from
pool, or do nothing.
3.Call object's deconstructor when "delete" object if constructor's been
calling at "new" object
3.Call object's deconstructor when destroy objectpool if constructor's
been calling at memory allocating
4.Can pass an function object to be invoke when "new" object, this can be
used as a constructor if object's constructor don't be invokded when "new"
object
5.Thread safe can be enable/disable by tempalte parameter
6.Callback can be raw pointer is T is not inherit from enable_shared_from
this
can be shared_ptr vers vice.

There are several tasks need to do, like the allnodesset can be generated
at callring of foreach. Delegate memory allocating to allocator, etc..

 The whole project and unit test can be found at
https://maxsrecyclebin.svn.sourceforge.net/svnroot/maxsrecyclebin/objectpool/

Is there any comments?
Thanks
//////////////////////////////////////////////////////////////////////////////////////
#include <istream>
#include <list>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <set>
#include <algorithm>
#include <boost/type_traits.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/thread/pthread/mutex.hpp>
namespace maxutility {
enum InitialType {None,ObjInitial,PoolAllocate};
template <typename T>
class DummyCallableObj
{
public:
    void operator ()(boost::shared_ptr<T> &ptr)
    {
        //do nothing
    }
};
template<bool isthreadsafe>
class obthreadlock;
template<>
class obthreadlock<true>
{
public:
    void lock(){obmutex.lock();}
    bool try_lock(){return obmutex.try_lock();}
    void unlock(){obmutex.unlock();}
private:
    boost::mutex obmutex;
};
template<>
class obthreadlock<false>
{
public:
    void lock(){};
    bool try_lock(){return true;};
    void unlock(){};
};
template <typename T,bool isthreadsafe=false,typename
InitalFunction=DummyCallableObj<T> >
class ObjectPool
{
#define LOCAL_LOCK boost::lock_guard<obthreadlock<isthreadsafe> >
lg(obthreadlock_);
protected:
    /**
     * @brief Declaration for furture usage
     **/
    typedef T Node;
    typedef std::list<char *> FRAGMENTTYPE;
    typedef std::list<Node *> NODELIST;

public:
    ObjectPool(InitialType initialtype=ObjInitial,size_t
initialsize=512,size_t maxsize=0)
    {

        busyCount=0;
        this->poolsize=0;
        this->initialtype=initialtype;
        this->maxsize=maxsize;
        extend(initialsize);
    }
    ObjectPool(InitalFunction initalFunction=DummyCallableObj<T>(),
               InitialType initialtype=PoolAllocate,
               size_t initialsize=512,
               size_t maxsize=0)
//:ObjectPool(initialtype,initialsize,maxsize) //Delegating constructors,
c++11 only
    {
        busyCount=0;
        this->poolsize=0;
        this->initialtype=initialtype;
        this->maxsize=maxsize;
        this->initalFunction=initalFunction;
        extend(initialsize);
    }
    ~ObjectPool()
    {
        if(0!=busyCount)
            throw new std::exception();
        if(PoolAllocate==initialtype)
            for(Node *p:allnodes)
                p->~Node();
        for(char *pFragment:fragments)
            delete pFragment;
    }
    virtual boost::shared_ptr<T> create()
    {
        LOCAL_LOCK;
        boost::shared_ptr<T>
ptr(static_cast<T*>(getFreeNode()),boost::bind(&ObjectPool<T,isthreadsafe,InitalFunction>::free,this,_1));
        initalFunction(ptr);
        return ptr;
    }

    bool empty()
    {
        return !busyCount;
    }
    size_t size()
    {
        return busyCount;
    }
    size_t capacity()
    {
        return poolsize;
    }
    template <typename FUNCTION>
    void foreach(FUNCTION f)
    {
        LOCAL_LOCK;
        NODELIST freenodes=this->freenodes; //make a local copy
        freenodes.sort();
        NODELIST busynodes(allnodes.size());
        typename NODELIST::iterator busynodesend=std::set_difference(

allnodes.begin(),allnodes.end(),freenodes.begin(),freenodes.end(),busynodes.begin()
        );

        for(typename NODELIST::iterator iter=busynodes.begin();
            iter!=busynodesend;
            iter++)
            {
                invokeFunction<FUNCTION,Node,
                boost::is_base_of<boost::enable_shared_from_this<Node>,Node
>::value >()(f,*iter);
            }
    }
protected:
    template<typename _Function,typename N,bool isuseshareptr>
    class invokeFunction;
    template<typename _Function,typename N>
    class invokeFunction<_Function,N,false>
    {
    public:
        void operator ()(_Function __f,N *p)
        {
            __f(p);
        }
    };
    template<typename _Function,typename N>
    class invokeFunction<_Function,N,true>
    {
    public:
        void operator ()(_Function __f,N *p)
        {
            boost::shared_ptr<N> ptr=p->shared_from_this();
            __f(ptr);
        }
    };

protected:
    void free(T *p)
    {
        LOCAL_LOCK;
        if(!p)
            return;
        destroyObj(static_cast<Node*>(p),ObjInitial);
        //removeBusyNode(static_cast<Node*>(p));
        freenodes.push_back(static_cast<Node*>(p));
        busyCount--;
    }
    Node *getFreeNode()
    {
        Node *ptr=nullptr;
        if(freenodes.empty()) //no new free node
            if(!extend()) //try to extend
                return ptr; //false
        ptr=freenodes.front(); //now it must contain free node
        freenodes.pop_front();

        constructObj(ptr,ObjInitial);
        busyCount++;
        return ptr;
    }
    bool extend(size_t size=0)
    {
        if((0!=maxsize&&poolsize>=maxsize&&poolsize!=0)

          )
            return false; //we reach the maximum size
        //poolsize=0 first allocation
        //size=0 extend twice size of current size
        //poolsize=size=0 we got a problem
        size_t extSize=((0==poolsize)?size:2*poolsize);
        char *pFragment=new char[extSize*sizeof(Node)];
        if(!pFragment)
            return false;
        fragments.push_back(pFragment);
        poolsize+=extSize;
        for(Node *p=(Node*)pFragment; extSize--; p++)
        {
            constructObj(p,PoolAllocate);
            freenodes.push_back(p);
            allnodes.push_back(p);
        }
        allnodes.sort();
        return true;
    }
    void constructObj(Node *p,InitialType phase)
    {
        if(phase==initialtype)
            ::new(p)Node;
    }
    void destroyObj(Node *p,InitialType phase)
    {
        if(phase==initialtype)
            p->~Node();
    }

    size_t poolsize;
    InitialType initialtype;
    size_t maxsize;
    FRAGMENTTYPE fragments;
    NODELIST freenodes;
    NODELIST allnodes;
    size_t busyCount;
    InitalFunction initalFunction;
    obthreadlock<isthreadsafe> obthreadlock_;
};
};



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net