代码改变世界

object pool

2013-09-19 13:42  yu_yu  阅读(558)  评论(0编辑  收藏  举报

这是一个简单易用的对象池,很多系统对资源的访问快捷性及可预测性有严格要求,列入包括网络连接、对象实例、线程和内存。而且还要求解决方案可扩展,能应付存在大量资源的情形。

object pool针对特定类型的对象循环利用,这些对象要么创建开销巨大,要么可创建的数量有限。而且在pool中的对象需要做到无状态。

 

如何使用

utility::object_pool_t<int> pool1([]()
{
return std::make_shared<int>(10);
});

{
auto t = pool1.get();
}

指定类型,创建一个pool对象,同时提供创建对象函数。

获取接口get,返回一个std::shared_ptr<T>对象,在该对象析构时自动返回到pool中,不需要额外的释放接口

 

实现

#ifndef __UTILITY_OBJECT_POOL_HPP
#define __UTILITY_OBJECT_POOL_HPP


#include <memory>
#include <list>
#include <functional>
#include <cstdint>


namespace utility {

template < typename T >
struct object_pool_traits_t;


template < typename T, typename AllocatorT >
struct object_pool_traits_t<std::list<std::shared_ptr<T>, AllocatorT>>
{
typedef std::shared_ptr<T> value_t;

static value_t pop(std::list<value_t, AllocatorT> &l)
{
if( l.empty() )
{
return value_t();
}
else
{
value_t val = l.front();
l.pop_front();
return val;
}
}


static void push(std::list<value_t, AllocatorT> &l, value_t && val)
{
l.push_back(std::move(val));
}


template < typename HandlerT >
static void for_each(std::list<value_t, AllocatorT> &l, const HandlerT &handler)
{
std::for_each(l.cbegin(), l.cend(), handler);
}


static std::uint32_t size()
{
return l.size();
}
};



template <
typename T,
typename C = std::list<std::shared_ptr<T>>
>
struct object_pool_t
{
typedef std::shared_ptr<T> value_t;
typedef C queue_t;
typedef std::shared_ptr<queue_t> pool_t;

typedef std::function<value_t()> create_handler_t;
static_assert(std::is_same<value_t, typename queue_t::value_type>::value, "container value_type must be std::shared_ptr<T> type");

create_handler_t create_handler_;
pool_t pool_;


object_pool_t(const create_handler_t &create_handler)
: pool_(std::make_shared<queue_t>())
, create_handler_(create_handler)
{
if( create_handler_ == nullptr )
create_handler_ = []()->value_t{ return std::make_shared<value_t::element_type>(); };
}


template < typename AllocatorT = std::allocator<char> >
value_t get(const AllocatorT &allocator = AllocatorT())
{
value_t obj = object_pool_traits_t<queue_t>::pop(*pool_);
if( !obj )
obj = create_handler_();

return std::shared_ptr<T>(obj.get(),
[=](T *) mutable
{
object_pool_traits_t<queue_t>::push(*pool_, std::move(obj));
}, allocator);
}


value_t raw_aciquire()
{
value_t obj = object_pool_traits_t<queue_t>::pop(*pool_);
if( !obj )
obj = create_handler_();

return obj;
}


void raw_release(value_t &&val)
{
object_pool_traits_t<queue_t>::push(*pool_, std::move(val));
}


void for_each(const std::function<void(const value_t &)> &handler)
{
object_pool_traits_t<queue_t>::for_each(*pool_, handler);
}


std::uint32_t size() const
{
return object_pool_traits_t<queue_t>::size(*pool_);
}
};
}

#endif

如何扩展

1. 先扩展pool容器

namespace utility  {

template < >
struct object_pool_traits_t<tbb::concurrent_bounded_queue<std::shared_ptr<int>>>
{
typedef std::shared_ptr<int> value_t;
typedef tbb::concurrent_bounded_queue<value_t> container_t;


static value_t pop(container_t &l)
{
value_t v;
if( !l.try_pop(v) )
return std::make_shared<int>();

return v;
}

static void push(container_t &l, value_t && val)
{
l.push(val);
}
};

}
2. 定义类
utility::object_pool_t<int, tbb::concurrent_bounded_queue<std::shared_ptr<int>>> pool2([]()
{
return std::make_shared<int>(1);
});
3. 获取资源
{
auto t = pool2.get(tbb::tbb_allocator<char>());
}

{
auto n = pool2.raw_aciquire();
*n = 12;
pool2.raw_release(std::move(n));
}


over