仿照Loki写的ResourcePool,大家给点意见

Yssss1980 2004-05-08 03:43:54
#if !defined __RESOURCE__POOL__H__
#define __RESOURCE__POOL__H__

#include <vector>
#include <cassert>
#include <Threads.h>
#include <Singleton.h>

namespace xwtec
{
namespace Private
{
//Notice:
//这里不需要定义析构函数来释放资源,因为这个类会在容器中使用,避免出现多次删除的问题
//它的资源由其Host Class来处理
template<class Resource>
struct ResourceWithStatus
{
ResourceWithStatus(Resource *pRes):pRes_(pRes),isUsed_(false)
{
}
operator Resource*()
{
return pRes_;
}
bool isUsed_;
Resource *pRes_;
};
};

template
<
class Resource,
template <class> class CreationPolicy = Loki::CreateUsingNew,
template <class> class ThreadingModel = Loki::SingleThreaded
>
class ResourcePool
{
std::vector< Private::ResourceWithStatus<Resource> > ResVec_;
public:
ResourcePool()
{
}
virtual ~ResourcePool()
{
DestoryAllResource();
}
private:
Resource *CreateResource()
{
Resource *pRes = CreationPolicy<Resource>::Create();
if(pRes != 0)
{
Private::ResourceWithStatus<Resource> rws(pRes);
ResVec_.push_back(rws);
}
return pRes;
}
public:
Resource *GetResource()
{
typename ThreadingModel<ResourcePool>::Lock guard;
(void)guard;

unsigned int i =0;
for(;i<ResVec_.size();++i)
{
if(!ResVec_[i].isUsed_)
{
ResVec_[i].isUsed_ = true;
return ResVec_[i].pRes_;
}
}
Resource *pRes = CreateResource();
if(pRes!=0)
{
ResVec_[i].isUsed_=true;
}
return pRes;
}

bool ReleaseResource(Resource * &pRes)
{
typename ThreadingModel<ResourcePool>::Lock guard;
(void)guard;

for(unsigned int i=0;i<ResVec_.size();++i)
{
if(ResVec_[i].pRes_ == pRes)
{
assert(ResVec_[i].isUsed_);
ResVec_[i].isUsed_ = false;
pRes = 0;
return true;
}
}
return false;
}

void DestoryAllResource()
{
typename ThreadingModel<ResourcePool>::Lock guard;
(void)guard;

for(unsigned int i=0;i<ResVec_.size();++i)
{
delete ResVec_[i].pRes_;
}
ResVec_.clear();
}
};

template <class Resource,class ResourcePool_=ResourcePool<Resource> >
class SmartResource
{
private:
Resource *pRes_;
ResourcePool_& Pool_;
public:
Resource * operator ->()
{
return pRes_;
}
SmartResource(ResourcePool_ & pool):Pool_(pool)
{
pRes_ = Pool_.GetResource();
}
~SmartResource()
{
Pool_.ReleaseResource(pRes_);
}
private:
//disable copy ctor and operator=
template<class R,class P>
SmartResource(SmartResource<R,P> & other);

template<class R,class P>
SmartResource<Resource,ResourcePool_>& operator=(SmartResource<R,P> & other);
};
};

#endif
...全文
274 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
Wolf0403 2004-06-14
  • 打赏
  • 举报
回复
1、
C++ 中可以说有这样一个公认的习惯:指针指向的内存是需要管理的,引用不需要。所以我只在 Handle 里面提供返回引用的方法。如果客户代码通过 Handle h; delete h.operator->(); 这样的代码来故意进行“非常规”操作,我也就没什么办法了。

2、
暂时没有发现好的解决办法,认输。

3、
这是一个设计抉择的问题。譬如我用 Pool 实现一个 ThreadPool,如果在 Job 超过 Working Thread count 的时候就自动增加 Working Thread (resource) 的话,有可能导致很多不必要的线程上下文切换操作,反而降低效率失去了使用 Pool 的意义。Pool 是为了控制资源总数和访问而存在的。如果要自动生成,还是用一个 Factory 更合理。。。
Wolf0403 2004-06-13
  • 打赏
  • 举报
回复
template <typename _RscT, class _Traits>
class Pool
:public NonCopyable<Pool<_RscT, _Traits> >

这种 CRTP 技法是 Policy 惯常使用的,其实不必。NonCopyable 不必是 template class,没有虚拟函数同样可以使用。

Pool 应该使用 Singleton,用一个 Policy class 也可以解决。
注意,Pool 的所有公开方法没有返回任何“赤裸裸”的 _RscT 类型的东西,强制通过 Handle 来操作,因此避免了任何的重复删除的可能性。
Wolf0403 2004-06-13
  • 打赏
  • 举报
回复
#include <vector>
#include <windows.h>
using namespace std;

template <typename T>
class NonCopyable
{ // NonCopyable: policy class disabling copy ctor and operator=
public:
NonCopyable(){}
~NonCopyable(){}
private:
NonCopyable(const NonCopyable &);
NonCopyable & operator=(const NonCopyable &);
};

template <typename _RscT, class _Traits>
class Pool
:public NonCopyable<Pool<_RscT, _Traits> >
{
public:
class Handle;
friend class Handle;

class Handle
{ // should be a corresponding const_Handle class
public:
Handle(Pool & p, unsigned os):offset_(os), pool_(p)
{
assert(offset_ < pool_.used_.size());
pool_.used_[offset_] = true;
}
_RscT & operator*()
{ return p.rsc_[offset_];}
_RscT * operator->()
{ return & p.rsc_[offset_];}
operator bool() const
{ return offset_ < pool_.used_.size();}
~Handle()
{ pool_.used_[offset_] = false; }
private:
const unsigned offset_;
Pool & pool_;
};

void CreateResource()
{
rsc_.push_back(_Traits::Create());
used_.push_back(false);
}

Handle GetResource()
{
vector<bool>::iterator iter = used_.begin();
for (; iter != used_.end(); ++iter)
{
if (!(*iter))
return Handle(*this, iter - used_.begin());
}
return Handle(*this, used_.size()); // invalid value
}

// No need for "ReleaseResource": Each time life cycle of
// "used" state of each resource is managed by Handle,
// which is the single entrance to the resource.

// Calling "DestoryAllResources" during lifecycle of Pool
// is a design decision. I chose "No".

~Pool ()
{
typename vector<_RscT>::iterator iter = rsc_.begin();
for (; iter != rsc_.end(); ++iter)
{
_Traits::Destory(*iter);
}
}
private:
vector<_RscT> rsc_;
vector<bool> used_;
};

//===============================================================
struct EventTraits
{
static HANDLE Create()
{ return ::CreateEvent(0, false, false, 0); }
static void Destory (HANDLE & hd)
{ ::CloseHandle(hd); }
};

int main()
{
Pool<HANDLE, EventTraits> p;
p.CreateResource();
Pool<HANDLE, EventTraits>::Handle handle = p.GetResource();
Pool<HANDLE, EventTraits>::Handle handle2 = p.GetResource();
assert(!handle2);
system("PAUSE");
}
Wolf0403 2004-06-13
  • 打赏
  • 举报
回复
哈哈!
1、谢谢楼上二位

2、不是说 SmartResource 本身有什么问题。。。
ResourcePool 提供了如下接口:
public:
Resource *GetResource()

使客户代码得到了直接的 Resource 指针,几乎可以认为是诱惑人们直接“赤裸裸”地操作,从而使 SmartResource 形同虚设。

3、看错了!抱歉!

Yssss1980 2004-06-13
  • 打赏
  • 举报
回复
几个问题,我想说一说

1.只要你提供了客户访问Resource的指针或引用,客户端一定可以删除它,不是吗?
_RscT & operator*()
{ return p.rsc_[offset_];}
_RscT * operator->()
{ return & p.rsc_[offset_];}
除非你象Windows API,对资源的访问全部通过API传handle来访问

2.NonCopyable这个模板类只能禁止相同类型资源池的拷贝吧,不能禁止不同资源池的拷贝,显然这个也是不合法的

3.资源池应该能自动CreateResource,就是说资源不够用的时候,能够自动扩张,以满足需要。
Yssss1980 2004-06-12
  • 打赏
  • 举报
回复
谢谢楼上帮助我回答第一个问题

2.SmartResource 是为了设计一个安全使用资源的类,也就是自动释放资源,避免忘记释放。跟auto_ptr有点象吧

3.不可能出现double delete的事情,因为只有DestoryAllResource才删除,另外ResVec_.clear(); 不可以少,因为资源的引用都存在这个数组里面,所以DestoryAllResource当然要清空它

4.Loki里面似乎没有这个东西

Wolf说:
而且,看来这里 ResourcePool 的元素类型也必须是一个包装了非内存资源的 RAII 类。。。这么多的间接层,直接导致了设计的复杂和效率的低下。建议使用 traits 技术。
Answer:
Code is King。请给出你的代码。
EricZhuo 2004-06-11
  • 打赏
  • 举报
回复
1、
bool ReleaseResource(Resource * &pRes)
{
typename ThreadingModel<ResourcePool>::Lock guard;
(void)guard; // 神奇!做什么用的?

为了取消“有没使用的变量”warning
hxblvc 2004-06-11
  • 打赏
  • 举报
回复
先顶一下,现慢慢看
Wolf0403 2004-06-11
  • 打赏
  • 举报
回复
而且,看来这里 ResourcePool 的元素类型也必须是一个包装了非内存资源的 RAII 类。。。这么多的间接层,直接导致了设计的复杂和效率的低下。建议使用 traits 技术。
Wolf0403 2004-06-11
  • 打赏
  • 举报
回复
1、
bool ReleaseResource(Resource * &pRes)
{
typename ThreadingModel<ResourcePool>::Lock guard;
(void)guard; // 神奇!做什么用的?

2、有 Resource *GetResource() 的存在,这个 SmartResource 是不是有点形同虚设?而且直接操作 Resource * 也可能使得 Private::ResourceWithStatus<Resource> 的状态失去同步。

3、通过 DestroyAllResource 和 ReleaseResource 的共同作用,完全可能导致 double delete 事故的发生。。。尤其在使用了 SmartResource 的情况下。

void DestoryAllResource()
{
typename ThreadingModel<ResourcePool>::Lock guard;
vector<Private::ResourceWithStatus<Resource> >::iterator iter(ResVec_.begin());
for(;iter != ResVec_.end(); ++iter)
{
if (iter->isUsed_)
{
delete iter->pRes_;
iter->isUsed_ = false;
}
}
ResVec_.clear(); /* 并不释放内存,ResourceWithState 也没有析构函数,建议删除这句“废话”*/
}

4、//disable copy ctor and operator=
我猜想 Loki 可能有相应的 Policy class 可以直接用吧。。。这个纯属猜测
superxxx 2004-06-11
  • 打赏
  • 举报
回复
看不懂
qwertasdfg123 2004-06-10
  • 打赏
  • 举报
回复
好长哦
justaseeker 2004-06-10
  • 打赏
  • 举报
回复
mark支持一下
cgsw12345 2004-05-10
  • 打赏
  • 举报
回复
UP!收藏先!
carambo 2004-05-08
  • 打赏
  • 举报
回复
我也得慢慢看。up一下先
sharkhuang 2004-05-08
  • 打赏
  • 举报
回复
慢慢看.
freefalcon 2004-05-08
  • 打赏
  • 举报
回复
先mark支持一下
whongun 2004-05-08
  • 打赏
  • 举报
回复
up一下先
languagec 2004-05-08
  • 打赏
  • 举报
回复
一楼!

24,855

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧