2009-11-09 78 views
6

由於使用Singleton模式實現記錄器的洪泛示例,我剛剛爲我的程序編寫了一個簡單的C++記錄器。然而,由於着名的雙重檢查鎖定方法已知不再是線程安全的,我不知道我是否應該:使用單例模式的簡單C++記錄器

1)忘記在這種情況下使用Singleton模式?

2)繼續使用雙重檢查鎖定,即使它是不安全的?

3)使用昂貴的純同步鎖定方法來訪問其公共接口?

有什麼建議嗎?

+1

哇,我沒想到反應速度如此之快。我只是意識到我犯了一個愚蠢的錯誤。在我的情況下,基本上有兩組需要保護的接口:getInstance(),其餘的是記錄器客戶端初始化各種日誌設置。我的錯誤是,我花了很多時間找到一種方法來保護這兩種類型的接口,希望平衡效率。爲什麼我必須使用一個,而且只有一個方法?我可以使用Arkaitz或stefaanv的getInstance()建議;然後使用基本同步鎖進行設置初始化。 – shiouming 2009-11-09 15:16:01

回答

16

使用Meyers Singleton。如果你使用gcc,至少初始化是線程安全的。

class Singleton{ 
    Singleton(){ 
    //This is threadsafe in gcc, no mutex required 
    } 
    static Singleton * instance(){ 
     static Singleton myinstance; 
     return &myinstance; 
    } 
}; 

GCC衛士靜態當地人建造,除非你禁用與-fno線程安全的,靜態的,我最近寫了那篇關於here

+0

難道你不希望instance()是靜態的嗎? – Aaron 2009-11-09 14:18:10

+0

亞倫,你是對的。 – 2009-11-09 14:20:31

+0

+1,我曾經用WindRiver C/C++編譯器(之前的Diab)花了足夠的時間解決這個問題。 – 2009-11-09 14:42:23

1

與線程應用中,我更喜歡使用與單身一個initialize()函數斷言確保在第一個實例()之前使用initialize()。從主線程調用initialize()。我不認爲懶惰的實例化是單身人士的關鍵特徵,特別是對於記錄者。雖然Arkaitz的答案更加優雅,但我的答案避免了在所有平臺上的線程問題,其中包含一個額外函數的成本,以及一些啓動期間有關依賴關係的單例實例化問題(由斷言和當然幫助:明智地使用單例)。

+0

我傾向於喜歡這個答案,但有一點需要注意的是,在預初始化代碼期間,您無法使用日誌記錄。這通常不是什麼大問題,但我已經讓我咬了一兩次。 – 2009-11-09 14:37:43

+0

@Michael:當我們決定採用這種方法時,我實際上建議使用你的答案:在主線程中訪問。但是這種方法適用於我們,並且確保單例始終在主線程中初始化。如果訪問將從主線程中移除,我們只會發現第一次出現問題(在域中) – stefaanv 2009-11-09 14:47:51

+0

我現有的代碼非常接近這種方法。但是,我還想知道是否應該假設記錄器的客戶端代碼將始終正確使用/初始化記錄器,或者是否應該在內部執行任何檢查。 – shiouming 2009-11-09 15:00:11

1

一種方法是確保在應用程序啓動第二個線程之前首次訪問記錄器。通過在您知道沒有任何爭用的情況下訪問單例,確保後續訪問始終會找到預先存在的對象,並且應該完全避免該問題。

0

你並不需要單獨的Initialize()函數,因爲這會污染你的單例接口。只需獲得單例實例

VERIFY(NULL != Logger::Instance()); 

在任何其他線程有機會訪問它之前。

+0

你不需要檢查singelton是否爲NULL。它存在或不存在。返回參考singelton gurantess它存在。 – 2009-11-09 19:41:05

+0

謝謝馬克。我同意singleton getter必須返回引用,而不是指針。我的這一行指的是上面關於邁耶斯單身人士的剪貼畫,它通過指針返回。儘管它看起來不會失敗,但你永遠不知道誰會修改你的代碼。所以這裏的VERIFY只是未來程序員的時間囊。 – BostonLogan 2009-11-09 23:25:57