我运行到kindof一个恼人的问题,并会需要一些建议...线程安全懒get和释放
比方说,我有一堆小MyObject来的,可以构建更大MyExtendedObject的。 MyExtendedObject的是大和CPU占用因此施工很懒,我尽量不尽快从内存中删除它们尽可能:
MyExtendedObject * MyObject::GetExtentedObject(){
if(NULL == ext_obj_){
ext_obj_ = new MyExtendedObject;
}
++ref_;
return ext_obj_;
}
void MyObject::ReleaseExtentedObject(){
if(0 == (--ref_))
{
if(NULL != ext_obj_)
{
delete ext_obj_;
ext_obj_ = NULL;
}
}
}
扩展对象仅在开始构建一次,当最后一个来电者释放他们被摧毁。请注意,有些可能会被构建多次,但这不是一个问题。
现在,这绝对不是线程安全的,所以我做了一个“天真”的线程安全的实现:
MyExtendedObject * MyObject::GetExtentedObject(){
Lock();
if(NULL == ext_obj_){
ext_obj_ = new MyExtendedObject;
}
++ref_;
Unlock();
return ext_obj_;
}
void MyObject::ReleaseExtentedObject(){
Lock();
if(0 == (--ref_))
{
if(NULL != ext_obj_)
{
delete ext_obj_;
ext_obj_ = NULL;
}
}
Unlock();
}
这是更好,但现在我花很多时间锁定和解锁一些非忽略量..
我有这种感觉,我们只有在构建或破坏时才能支付锁定/解锁。
我想出了这个解决方案:
MyExtendedObject * MyObject::GetExtentedObject(){
long addref = InterlockedCompareExchange(&ref_, 0, 0);
long result;
do{
result = addref + 2;
} while ((result-2) != (addref = InterlockedCompareExchange(&ref_, result, addref)));
if(0 == (result&1)){
Lock();
if(NULL == ext_obj_){
ext_obj_ = new MyExtendedObject;
InterlockedIncrement(&ref_);
}
Unlock();
}
return ext_obj_;
}
void MyObject::ReleaseExtentedObject(){
long release = InterlockedCompareExchange(&ref_, 0, 0);
long result = 0;
do{
result = release - 2;
} while ((result+2) != (release = InterlockedCompareExchange(&ref_, result, release)));
if(1 == result)
{
Lock();
if(1 == InterlockedCompareExchange((long*)&ref_, 0, 1))
{
if(NULL != ext_obj_)
{
delete ext_obj_;
ext_obj_ = NULL;
}
}
Unlock();
}
}
几点说明:
我不能使用升压。我想但实在不行。
我只使用CompareExchange和Incr/Decr。不要问。
我使用ref_的第一个位来存储构造状态(构造/未构造)和其他位来进行参考计数。这是我发现通过原子操作同时管理2个变量(参考计数和施工状态)的唯一途径。
现在的一些问题:
你认为这是100%的防弹?
你知道一些更好的解决方案吗?
编辑:有人建议使用shared_ptr。一个与shared_ptr工作解决方案!请注意,我需要:懒惰建设和破坏时,没有人不再使用它。
没有必要将'Extended'拼写为'Extented'或'Extanted',更不用说在同一个程序中。 – 2010-10-08 15:13:24
谢谢,我试图纠正它。英语不是我的母语:) – Julio 2010-10-08 15:27:18