目錄
1 餓漢模式
在程序啓動或單件模式類被加載的時候,單件模式實例就已經被創建。
主要注意如下四個部分:
- 構造函數私有化或者保護化
- .禁止拷貝和賦值
- 靜態的共有接口
- 初始化靜態數據成員
2 懶漢模式
當程序第一次訪問單件模式實例時才進行創建。
懶漢模式下,在定義m_instance變量時先等於NULL,在調用GetInstance()方法時,在判斷是否要賦值。這種模式,並非是線程安全的,因爲多個線程同時調用GetInstance()方法,就可能導致有產生多個實例。要實現線程安全,就必須加鎖。
3 多線程安全的懶漢單例模式
3.1 普通加鎖方式
這種GetInstance()方法,每次進來都要加鎖,會影響效率。然而這並不是必須的,於是又對GetInstance()方法進行改進。
3.2 雙鎖機制
上述的方式可能會有意料不到的後果。問題的來源是CPU的亂序執行,C++的New操作實際上包含了兩個步驟:(1)分配內存;(2)調用構造函數。
實際上,m_instance = new T()包含了三個步驟:
- 分配內存
- 在內存的位置上調用構造函數
- 將內存的地址賦值給pInst
因爲(2)和(3)是可以顛倒的,所以可以出現這樣的情況:m_instance的值已經不是NULL,但對象仍然沒有構造完畢。如果另外一個線程對GetInstance的調用,此時第一個if爲false,這樣就會返回一個未構造完成的對象,此時可能會導致程序崩潰。
解決思路:用一個局部變量過渡下就ok了
在linux提供了一個叫pthread_once()的函數,它保證在一個進程中,某個函數只被執行一次。