完整代码下载

数据库连接池, 线程池等等的概念, 相信大家不会陌生. 在编写服务器程序时, 这些概念的应用犹如家常便饭. 至于为什么要用”池”, 通俗的讲, 就是”避免频繁的资源分配与释放, 从而提高程序性能”, 往抽象里说, 就是”用空间换时间”.

下面将介绍一个通用资源池的实现. 受益于shared_ptr的自定义deleter, 它的接口极为简单

template<typename R>
struct ResourcePool : boost::noncopyable {
  ///资源类型
  typedef R ValueType;
  ///资源的智能指针
  typedef boost::shared_ptr<R> ValuePtr;
  ///得到池的大小(包括正被使用的, 和闲置的资源个数)
  std::size_t size() const;
  ///得到闲置的资源个数
  std::size_t unused() const;
  ///释放闲置的资源
  void shrink();
  ///获取资源, 如果有闲置资源, 就直接使用闲置资源, 如果没有就分配一个(分配失败的时候会返回空指针)
  ValuePtr get();
  template <typename A>
  explicit ResourcePool(A allocator);
};

 

其中最核心的一个方法就是get. 你可能已经发现了, 这里没有回收的方法. 那么资源是怎么被回收, 从而重复利用的呢? 关键在于get的返回值, get返回一个资源的智能指针, 这个指针指针的deleter是定制的

struct Deleter {
  Deleter(const ProxyWeakPtr & proxy, const ValuePtr & res):
    _proxy(proxy), _res(res)
  {}
  void operator()(void *) {
    /// try lock proxy
    ProxyPtr proxy = _proxy.lock();
    if(proxy)
    proxy->recycle(_res);
    ///else, the resource pool gone. nothing to do, and _res will do the right thing.
  }

private:
  /// proxy weak pointer
  ProxyWeakPtr _proxy;
  /// the real resource
  ValuePtr _res;
};

为了降低Deleter和ResourcePool的耦合, 这里引入了一个Proxy类… 越讲越复杂了, 还是看完整代码和示例吧

boost::shared_ptr<int> alloc(){
  return boost::shared_ptr<int>(new int(1));
}

int main(){
  lite::util::ResourcePool<int> pool(alloc);
  ///获取一个资源
  boost::shared_ptr<int> i = pool.get();
  assert(*i == 1);
  assert(pool.size() == 1);
  assert(pool.unused() == 0);
  ///释放获得的资源
  i.reset();
  assert(pool.unused() == 1);
  ///清理闲置资源
  pool.shrink();
  assert(pool.size() == 0);
  assert(pool.unused() == 0);

  return 0;
}

完整代码下载