Singleton之C 部分一

2021-09-10 08:33:45 字數 4415 閱讀 3699

由於c++不能保證靜態或者全域性物件的建構函式的呼叫順序以及析構順序。所以如果程式中有多個用此方法實現的singleton類,它們之間又有某種構造依賴關係和析構依賴關係,就會造成災難性的後果。所以,只有當肯定不會有構造和析構依賴關係的情況下,這種實現才是合適的。

>

優點實現簡單,多執行緒下安全

>

缺點如果有多個singleton物件的建立順序有依賴時,千萬別用;不是lazy loading,有些浪費。

scott meyer在<>3rd item4中提出了乙個解決方案,當將non-local static變數移動到靜態方法中成為local static變數的時候。c++保證當第一次靜態方法被呼叫的時候,才會建立該靜態變數。但是這裡有乙個疑問,建立順序能夠被控制了,可是析構順序呢?我們只知道程序結束的時候,local static 變數會被析構,而且按照建立順序的相反順序進行。如果幾個singleton類的析構函式之間也有依賴關係,並且這種依賴順序關係和lifo順序衝突,就會造成dead-reference問題。

>

優點實現簡單;用的時候才建立,比較節省。

>

缺點多執行緒下不安全;如果有多個singleton物件的析構順序有依賴時,要小心

dclp 就是 double-checked locking pattern.用於在多執行緒環境下保證只建立singleton物件。第一次check不用加鎖,但是第二次check和建立物件必須加鎖。還要注意編譯器可能會優化**,導致dclp模式失效。因此要使用volatile 修飾t* pinstance變數。先看一下 dclp的實現**:

class

singleton          }         return pinstance;     } private:     static singleton * volatile pinstance;     singleton() };

在c++98標準下,這是不可靠的。原因有三點:

一,執行順序得不到保證。編譯器會優化**,從而改變執行順序。         

pinstance = new singleton; 這個語句會分成三步完成:

1.分配記憶體,

2.在已經分配的記憶體上呼叫建構函式建立物件,

3.將物件賦值給指標pinstance.

但是這個順序很可能會被改變為1,3,2。如果a執行緒在1,3執行完後,b執行緒執行第乙個條件判斷if(pinstance ==0),此時鎖不能起到保護作用。b執行緒會認為pinstance已經指向有效物件,可以去使用了。嘿嘿,災難發生。主要原因是c++98標準中沒有包含多執行緒,只假定是單執行緒,編譯器的優化行為無視多執行緒環境,因此產生的優化**可能會被去掉你的**或者改變執行順序。我們沒有辦法在98標準的採用標準c++語言來解決這個問題,只能採用平台相關的多執行緒api和與之相容的編譯器來解決。因此,從本質上來說,基於98標準,此問題無解。

二,volatile對於執行順序也沒有幫助。

三,多處理器的系統,b處理器看到變數值的順序可能和a處理器寫變數值的順序不一致。

詳細解釋請參考scott meyers and andrei alexandrescu的**:

技術總是發展的,2011標準的出台給dclp帶來了曙光,真的還能用麼,拭目以待吧.  讓我們先下個結論:

>

缺點98標準下不可用

>

優點讓我們接受教育,包括andrei和scott meyer都犯過錯。

於是又回到老土的鎖方案,其實注意一下呼叫,還是能夠提高效率的。

class

singleton          return pinstance;     } private:     static singleton * volatile pinstance;     singleton() };

客戶呼叫時,在每個執行緒的開頭都獲得singleton* p = singleton::instance();以後就一直使用這個p變數,應該說還是能有效的降低同步的機會。避免頻繁呼叫singleton::instance()->就好。

>

優點實現簡單,執行緒安全

>

缺點客戶需要意識到,並且遵守少呼叫的原則。

嚴格來說,這是個策略。將要初始化的放到程式最開始初始化。在這個策略下,以上幾種方案都是可以的,包括dclp。因為總是在單執行緒中建立物件。

再分享一下我老師大神的人工智慧教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智慧的隊伍中來!

由於c++不能保證靜態或者全域性物件的建構函式的呼叫順序以及析構順序。所以如果程式中有多個用此方法實現的singleton類,它們之間又有某種構造依賴關係和析構依賴關係,就會造成災難性的後果。所以,只有當肯定不會有構造和析構依賴關係的情況下,這種實現才是合適的。

>

優點實現簡單,多執行緒下安全

>

缺點如果有多個singleton物件的建立順序有依賴時,千萬別用;不是lazy loading,有些浪費。

scott meyer在<>3rd item4中提出了乙個解決方案,當將non-local static變數移動到靜態方法中成為local static變數的時候。c++保證當第一次靜態方法被呼叫的時候,才會建立該靜態變數。但是這裡有乙個疑問,建立順序能夠被控制了,可是析構順序呢?我們只知道程序結束的時候,local static 變數會被析構,而且按照建立順序的相反順序進行。如果幾個singleton類的析構函式之間也有依賴關係,並且這種依賴順序關係和lifo順序衝突,就會造成dead-reference問題。

>

優點實現簡單;用的時候才建立,比較節省。

>

缺點多執行緒下不安全;如果有多個singleton物件的析構順序有依賴時,要小心

dclp 就是 double-checked locking pattern.用於在多執行緒環境下保證只建立singleton物件。第一次check不用加鎖,但是第二次check和建立物件必須加鎖。還要注意編譯器可能會優化**,導致dclp模式失效。因此要使用volatile 修飾t* pinstance變數。先看一下 dclp的實現**:

class

singleton          }         return pinstance;     } private:     static singleton * volatile pinstance;     singleton() };

在c++98標準下,這是不可靠的。原因有三點:

一,執行順序得不到保證。編譯器會優化**,從而改變執行順序。         

pinstance = new singleton; 這個語句會分成三步完成:

1.分配記憶體,

2.在已經分配的記憶體上呼叫建構函式建立物件,

3.將物件賦值給指標pinstance.

但是這個順序很可能會被改變為1,3,2。如果a執行緒在1,3執行完後,b執行緒執行第乙個條件判斷if(pinstance ==0),此時鎖不能起到保護作用。b執行緒會認為pinstance已經指向有效物件,可以去使用了。嘿嘿,災難發生。主要原因是c++98標準中沒有包含多執行緒,只假定是單執行緒,編譯器的優化行為無視多執行緒環境,因此產生的優化**可能會被去掉你的**或者改變執行順序。我們沒有辦法在98標準的採用標準c++語言來解決這個問題,只能採用平台相關的多執行緒api和與之相容的編譯器來解決。因此,從本質上來說,基於98標準,此問題無解。

二,volatile對於執行順序也沒有幫助。

三,多處理器的系統,b處理器看到變數值的順序可能和a處理器寫變數值的順序不一致。

詳細解釋請參考scott meyers and andrei alexandrescu的**:

技術總是發展的,2011標準的出台給dclp帶來了曙光,真的還能用麼,拭目以待吧.  讓我們先下個結論:

>

缺點98標準下不可用

>

優點讓我們接受教育,包括andrei和scott meyer都犯過錯。

於是又回到老土的鎖方案,其實注意一下呼叫,還是能夠提高效率的。

class

singleton          return pinstance;     } private:     static singleton * volatile pinstance;     singleton() };

客戶呼叫時,在每個執行緒的開頭都獲得singleton* p = singleton::instance();以後就一直使用這個p變數,應該說還是能有效的降低同步的機會。避免頻繁呼叫singleton::instance()->就好。

>

優點實現簡單,執行緒安全

>

缺點客戶需要意識到,並且遵守少呼叫的原則。

嚴格來說,這是個策略。將要初始化的放到程式最開始初始化。在這個策略下,以上幾種方案都是可以的,包括dclp。因為總是在單執行緒中建立物件。

Singleton之C 部分一

由於c 不能保證靜態或者全域性物件的建構函式的呼叫順序以及析構順序。所以如果程式中有多個用此方法實現的singleton類,它們之間又有某種構造依賴關係和析構依賴關係,就會造成災難性的後果。所以,只有當肯定不會有構造和析構依賴關係的情況下,這種實現才是合適的。優點實現簡單,多執行緒下安全 缺點如果有...

Singleton之C 部分一

由於c 不能保證靜態或者全域性物件的建構函式的呼叫順序以及析構順序。所以如果程式中有多個用此方法實現的singleton類,它們之間又有某種構造依賴關係和析構依賴關係,就會造成災難性的後果。所以,只有當肯定不會有構造和析構依賴關係的情況下,這種實現才是合適的。優點實現簡單,多執行緒下安全 缺點如果有...

C 設計模式之Singleton

一 功能保證乙個類僅有乙個例項。二 結構圖 三 優缺點 singleton模式是做為 全域性變數 的替代品出現的。所以它具有全域性變數的特點 全域性可見 貫穿應用程式的整個生命期,它也具有全域性變數不具備的性質 同型別的物件例項只可能有乙個。四 實現 教科書上的singleton定義如下 class...