好的,所以你不能沒有互斥體就可以完成它,但是你可以快速地完成這個互斥體。
首先聲明一個類來保存互斥體,和就緒標誌(以下InitMutex
)。當調用GrabMutex()
並且ready
是false
時,實際的互斥鎖被抓取。當調用ReleaseMutex()
時,它根據從GrabMutex()
發送的標誌執行正確的操作。第一次通過後,隨着靜態對象被初始化,準備就緒,因此不需要抓取互斥鎖。
現在,聲明一個類,在構造函數中調用GrabMutex()
,在析構函數中調用ReleaseMutex(flag)
,並在本地保存標誌(InitMutexHolder
)。
現在,在您的常規getSingleton
函數中實例化該類。這將確保單例初始化在第一次通過時被互斥,並且如果多個線程競爭他們將排隊在互斥體上。但是,一旦單身人士初始化,ready
成爲現實,並且訪問將會很快。在執行return theSingleton
之後,析構函數被神奇地調用,釋放互斥量(或者,如果互斥量未被採用,則不執行任何操作)。
但是,theSingleton()
函數中的主體代碼沒有變化,我們只在每個單例中添加了一個控制對象,並在調用中添加了一個管理線程安全的堆棧對象。
關於寫屏障的注意事項:因爲代碼是安全的,只要ready
爲假,並且ready
在對象初始化之後才能變爲真,代碼總體安全,假設寫操作立即可見。但是,ready=true
可能會延遲顯示,因爲在設置準備就緒後沒有寫屏障。然而,在此期間安全性仍然保持不變,因爲ready=false
是保守的,安全的情況。
class InitMutex
{
public:
InitMutex() : ready(false) { }
bool GrabMutex()
{
if (!ready)
{
mutex.Grab();
return true;
}
else
{
return false;
}
}
void ReleaseMutex(bool flagFromGrabMutex)
{
if (flagFromGrabMutex)
{
mutex.Release();
ready = true;
}
}
Mutex mutex;
bool ready;
};
class InitMutexHolder
{
public:
InitMutexHolder(InitMutex & m)
: initMutex(m)
{
inMutex = initMutex.GrabMutex();
}
~InitMutexHolder()
{
initMutex.ReleaseMutex(inMutex);
}
private:
bool inMutex;
InitMutex & initMutex;
};
static InitMutex singletonMutex;
static Singleton & getSingleton()
{
InitMutexHolder mutexHolder(singletonMutex);
{
static Singleton theSingleton;
return theSingleton;
}
}
以下是一個提示:您遇到的實現問題可能表明您嘗試執行的操作是錯誤的。 – Puppy 2012-04-03 13:47:34
爲什麼不使用全局變量而不是單例? – RedX 2012-04-03 13:51:49
@DeadMG我認爲最有可能我所問的是不可能的,但我不確定,所以我問=) – Alecs 2012-04-03 14:05:05