我運行到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