(載)對於c++中實現單例的討論

來源:互聯網
上載者:User
C++中實現單例,需要注意兩個問題:1.對記憶體的釋放。2.多線程下的健壯性。一下是CSDN上對於此問題的討論,先存一個。

#9樓 得分:5回複於:2008-02-18 20:26:40

你這個方法實現singleton不太好,會有多線程同步問題。
比如說一開始Singleton::instance為空白。然後有線程A和線程B同時訪問Singleton::GetInstance()。
有意思的是當任務A執行if (NULL == instance)這句時,剛判斷好instance確實為空白想調用new,或者時間可以再放款到正在執行new操作,但是還沒有返回;要命的是調度器由於某些原因一下子剝奪了線程A的執行又去執行線程B了。線程B順利地建立了一個instance執行個體,然後在某一時刻被調度器剝奪,再次執行線程A。OK,此時線程A從剛才的混沌中繼續執行它的new Singleton()的操作,這樣線程A所建立出來的就是另一個執行個體了。此時Singleton宣告破滅。

 

因此,能夠迎合多線程,乃至多處理的單件處理可以用以下方式:

C/C++ code
 class Singleton   {    private:              static Singleton instance;                    Singleton(void) {}            public:                                    static Singleton& GetInstance()             {     return instance;  }};Singleton Singleton::instance;

由於以上代碼中,Singleton::instance在程式載入後由初始化程式建立,因此對於應用程式不會有多線程困擾。如果是在多處理器或多核處理器環境下還要注意Singleton的成員函數中的一些同步。

#10樓 得分:0回複於:2008-02-18 20:35:14

回複Jim_King_2000:

 

在C++中使用singleton不用new主要不是因為要擔心如何delete。
如果你的應用程式指明了一個接收到一個訊息,由專門一個任務相應析構這個singleton執行個體,可以顯式地調用其解構函式:Singleton::GetInstance().~Singleton();
個人認為多任務機制下,用樓主的方法不太合適。而Jim_King_2000你的方法也有多線程問題。
因為局部static也不會對執行個體建立的操作原子化,除非建構函式內部具有鎖機制。或者也是通過某種訊息相應或通過狀態表示要建立一個Singleton執行個體,以確保在第一次調用Singleton::GetInstance()時只有一個任務執行,且操作過程中不被打斷,至少被打斷後不會被重入。

#14樓 得分:0回複於:2008-02-19 08:40:39

感謝各位的精彩回複,讓在下獲益匪淺啊。

 

liuworld說得確實是,靜態成員變數必須要在具體的cpp檔案中進行定義,類中出現的靜態成員變數只表示一種聲明。

感謝zenny-chen的提醒,我這種寫法在多線程環境下確實會有潛在問題,這是一種“惡漢式”的單例模式,就是需要的時候才建立執行個體,你提供的實現是一種“懶漢式”的單例模式,就是程式初始化載入的時候就首先建立好執行個體,然後每次引用即可。這確實可以解決一些多線程調度的問題,但是會提前佔用系統資源,當然,一般來說,“惡漢式”的單例模式已經基本上可以滿足我們的需求了。

對於“懶漢式”的單例模式,可以使用鎖和雙重判斷的方式來避免重複建立的問題。

例如:
  static Singleton *GetInstance()   
  {   
  if (NULL == instance)   
  {   
  lock()
  {   
  if (instance == NULL)   
  instance = new Singleton();   
  }  
  }   
  return instance;   
  }

#15樓 得分:0回複於:2008-02-19 08:56:27

還是去看《Modern C++ Design》吧。
另外,google "Pattern Hatching",等,純C、C++語言是無法安全實現多安全執行緒的singleton的。
勉強夠用的實現就可以了。
#16樓 得分:0回複於:2008-02-19 11:08:55

to zenny_chen:
你的方法有效率問題。只要使用了你的類,這個靜態對象都會被建立,無論該對象是否被使用者使用。如果該對象的構造和析構十分費時的話,這樣的方法會使效率大大降低。況且你的方法也並不能保證多安全執行緒。你怎麼知道靜態instance在構造的時候沒有別的線程正在調用GetInstance函數?

 

===========================================================================
如果你的應用程式指明了一個接收到一個訊息,由專門一個任務相應析構這個singleton執行個體,可以顯式地調用其解構函式:Singleton::GetInstance().~Singleton();  
===========================================================================
如果應用程式沒有用訊息怎麼辦?就算使用了訊息,你怎麼知道其它線程不需要Singleton對象了?萬一程式非正常退出怎麼辦(比如遇到未處理的異常或者非法操作)?

===========================================================================
而Jim_King_2000你的方法也有多線程問題。  
===========================================================================
1、我真的很希望這是我的方法。可惜現實不是這樣。這個方法屬於Scott Meyers。
2、這個方法是實現singleton的基礎。很多種singleton實現(如相互依賴的singleton,多線程下的singleton等等)都是依據這個方法實現的。
3、很多實現在一開始的時候並不考慮多線程。等到單線程的實現方法出來以後,再擴充到多線程上面或者由使用者自行加鎖。STL也並不是多線程的。但這並不影響使用,你自己加鎖就是了。

所以說singleton裡面不用new並不是因為多線程。而是沒有必要用new。建議你也翻翻《Modern C++ Design》。裡面有多線程singleton的實現。

#17樓 得分:0回複於:2008-02-19 20:19:58

To 樓上:

 

呵呵,在大多數場合我要讓應用程式一直使用這個Singleton執行個體。因此,我將它放在全域資料儲存區是個不錯的主意,尤其在嵌入式系統中甚至可以將它放入ROM中。因此,在嵌入式系統中,這個執行個體在機器引導後就存在了,直到複位或關機。所以你說我還要對它在程式運行時進行建立或析構就顯得荒謬了。

而本人沒那麼多時間去讀那些號稱為C++大師們寫的東西,我感興趣的部分是基於多核處理器的作業系統以及並行計算,和人工智慧等問題。

#18樓 得分:0回複於:2008-02-20 13:53:25

to 樓上:
==========================================
在大多數場合我要讓應用程式一直使用這個Singleton執行個體
==========================================
我們不應該假設這樣的場合。你的assumption不具有通用性。如果使用者的程式需要運行時建立singleton或者根本不建立某個singleton對象會怎樣?如果使用者只需要建立幾個不同的singleton對象中的一個或幾個(非全部)會怎麼樣?

 

==========================================
尤其在嵌入式系統中甚至可以將它放入ROM中
==========================================
同樣,這仍然不具有通用性。Singleton是可以根據需要建立的,這樣會大大限制了singleton的使用場合。

==========================================
因此,在嵌入式系統中,這個執行個體在機器引導後就存在了,直到複位或關機。所以你說我還要對它在程式運行時進行建立或析構就顯得荒謬了。  
==========================================
我們不應該假設這樣的場合,使用者的代碼不一定運行在嵌入式系統上。就算是在嵌入式系統中,singleton仍然可以根據需要建立,Scott Meyers的方法也適用,我們只要在應用程式開始的時候調用初始化函數(也就是包含singleton對象的定義的那個函數)即可。

==========================================
而本人沒那麼多時間去讀那些號稱為C++大師們寫的東西
==========================================
真沒時間就算了,如果有時間的話,還是要看一下。我們學數學,看得就是大師們的成果;你學人工智慧,書上的內容也是大師的成果;學C++也一樣。

#19樓 得分:0回複於:2008-02-20 13:53:44

to 樓上:
==========================================
在大多數場合我要讓應用程式一直使用這個Singleton執行個體
==========================================
我們不應該假設這樣的場合。你的assumption不具有通用性。如果使用者的程式需要運行時建立singleton或者根本不建立某個singleton對象會怎樣?如果使用者只需要建立幾個不同的singleton對象中的一個或幾個(非全部)會怎麼樣?

 

==========================================
尤其在嵌入式系統中甚至可以將它放入ROM中
==========================================
同樣,這仍然不具有通用性。Singleton是可以根據需要建立的,這樣會大大限制了singleton的使用場合。

==========================================
因此,在嵌入式系統中,這個執行個體在機器引導後就存在了,直到複位或關機。所以你說我還要對它在程式運行時進行建立或析構就顯得荒謬了。  
==========================================
我們不應該假設這樣的場合,使用者的代碼不一定運行在嵌入式系統上。就算是在嵌入式系統中,singleton仍然可以根據需要建立,Scott Meyers的方法也適用,我們只要在應用程式開始的時候調用初始化函數(也就是包含singleton對象的定義的那個函數)即可。

==========================================
而本人沒那麼多時間去讀那些號稱為C++大師們寫的東西
==========================================
真沒時間就算了,如果有時間的話,還是要看一下。我們學數學,看得就是大師們的成果;你學人工智慧,書上的內容也是大師的成果;學C++也一樣。

#20樓 得分:0回複於:2008-02-21 18:27:14

To Jim_King_2000 :

 

實際上在你的代碼中,由於使用了static,儘管在函數內,但是在載入器載入你的應用程式時仍然會為你的全域唯一的Singleton預留空間。只不過在調用GetInstance()時才調用建構函式(若有的話)。
而我的方法是在載入應用程式後,在初始化代碼中調用建構函式(如果有的話),但卻帶來了額外的安全性。實際上你所謂的儲存空間效率兩者是一樣的,而且結束生命的時間也一樣。除非你在建構函式中調用了記憶體動態分配函數,這樣很顯然,My Code將在初始化過程中分配空間;而你的將在第一次調用GetInstance()時分配。

#25樓 得分:0回複於:2008-02-22 13:44:54

我想這裡的 Singleton 是針對語言本身提出的解決方案;如果將之與系統相關的設計聯絡起來,未免有些牽強了。
當然實際應用的時候首先考慮的是系統的設計,然後才是具體的解決方案,而這裡的Singleton ,正是在C++中的
解決方案之一。和系統相關的設計應該被分離出去。設計首先要保證 Singleton 的應用是系統安全的,不管是
在何種環境下,這個條件成立以後,才會提到它的具體實現的設計——比如說這裡的C++ Singleton 。否則,會把
很多問題纏繞在一起,有時候根本不能解決問題
#29樓 得分:0回複於:2008-11-18 09:27:49

引用 4 樓 Jim_King_2000 的回複:

兄弟,singleton是不用new的。如果用了new,在什麼地方去delete它呢?singleton原理的基礎是局部static變數。
C/C++ codeclassSingleton 
{private:staticSingleton*instance; 

 

Singleton() 

}public:staticSingleton*GetInstance() 
{staticSingleton singleton;return&singleton

};
這種局部static變數只有在函數被調用的第一次才被建立,隨著程式的結束而結束…

private 保證只有一個實現,
static data + static member function !=singleton,
不容易銷毀,那本書叫做 不死的鳳凰

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.