在C++ and the Perils of Double-Checked Locking中,作者舉例說明了如何正確實施模式。在雙重鎖定的鎖定模式中獲取屏障
Singleton* Singleton::instance() {
Singleton* tmp = pInstance;
... // insert memory barrier (1)
if (tmp == 0) {
Lock lock;
tmp = pInstance;
if (tmp == 0) {
tmp = new Singleton;
... // insert memory barrier (2)
pInstance = tmp;
}
}
return tmp;
}
我無法弄清楚什麼,不過,如果是第一個內存屏障必須Singleton* tmp = pInstance;
後? (編輯:要清楚,我知道這個障礙是必要的,我不明白的是它是否必須在分配tmp後纔會出現)如果是這樣,爲什麼?以下內容無效嗎?
Singleton* Singleton::instance() {
... // insert memory barrier (1)
if (pInstance == 0) {
Lock lock;
if (pInstance == 0) {
Singleton* tmp = new Singleton;
... // insert memory barrier (2)
pInstance = tmp;
}
}
return pInstance;
}
我不是在猜測什麼編譯器可能會做一個專家,但即使對正確性並不重要,維護'tmp'確實避免了在普通(已經初始化)的情況下重複讀取全局狀態;如果你的週期非常困難,那麼雙重檢查鎖定似乎是一個好主意,避免重複讀取全局狀態可以確保你不會以其他方式犧牲某些收益; 'tmp'是堆棧本地的(所以共享不是問題);編譯器可以安全地避免重讀它,但可能無法優化第二次直接讀取「pInstance」。 – ShadowRanger
@ShadowRanger所以也許我的修改是有效的,但作者選擇以這種方式實現它爲您提到的優化?不幸的是,這篇論文並沒有解釋最終設計的理由,除了需要設置障礙。 – user1747505
@ user1747505您的更改不能保證將'pInstance'視爲非NULL的線程可以看到底層對象的初始化。您認爲哪種內存屏障可以確保這一點,考慮到將'pInstance'視爲非NULL的線程永遠不會遇到任何內存障礙。 –