C++實現執行緒安全的單例模式
轉載,原博地址:http://blog.csdn.net/fu_zk/article/details/11892095
一、懶漢模式:即第一次呼叫該類例項的時候才產生一個新的該類例項,並在以後僅返回此例項。
需要用鎖,來保證其執行緒安全性:原因:多個執行緒可能進入判斷是否已經存在例項的if語句,從而non thread safety.
使用double-check來保證thread safety.但是如果處理大量資料時,該鎖才成為嚴重的效能瓶頸。
1、靜態成員例項的懶漢模式:
class Singleton
{
private:
static Singleton* m_instance;
Singleton(){}
public :
static Singleton* getInstance();
};
Singleton* Singleton::getInstance()
{
if(NULL == m_instance)
{
Lock();//借用其它類來實現,如boost
if(NULL == m_instance)
{
m_instance = new Singleton;
}
UnLock();
}
return m_instance;
}
2、內部靜態例項的懶漢模式
這裡需要注意的是,C++0X以後,要求編譯器保證內部靜態變數的執行緒安全性,可以不加鎖。但C++ 0X以前,仍需要加鎖。
class SingletonInside
{
private:
SingletonInside(){}
public:
static SingletonInside* getInstance()
{
Lock(); // not needed after C++0x
static SingletonInside instance;
UnLock(); // not needed after C++0x
return instance;
}
};
二、餓漢模式:即無論是否呼叫該類的例項,在程式開始時就會產生一個該類的例項,並在以後僅返回此例項。
由靜態初始化例項保證其執行緒安全性,WHY?因為靜態例項初始化在程式開始時進入主函式之前就由主執行緒以單執行緒方式完成了初始化,不必擔心多執行緒問題。
故在效能需求較高時,應使用這種模式,避免頻繁的鎖爭奪。
class SingletonStatic
{
private:
static const SingletonStatic* m_instance;
SingletonStatic(){}
public:
static SingletonStatic* getInstance()
{
return m_instance;
}
};
//外部初始化 before invoke main
const SingletonStatic* SingletonStatic::m_instance = new SingletonStatic;
m_pInstance指向的空間什麼時候釋放呢?更嚴重的問題是,該例項的解構函式什麼時候執行?
如果在類的析構行為中有必須的操作,比如關閉檔案,釋放外部資源,那麼上面的程式碼無法實現這個要求。我們需要一種方法,正常的刪除該例項。
可以在程式結束時呼叫GetInstance(),並對返回的指標掉用delete操作。這樣做可以實現功能,但不僅很醜陋,而且容易出錯。因為這樣的附加程式碼很容易被忘記,而且也很難保證在delete之後,沒有程式碼再呼叫GetInstance函式。
一個妥善的方法是讓這個類自己知道在合適的時候把自己刪除,或者說把刪除自己的操作掛在作業系統中的某個合適的點上,使其在恰當的時候被自動執行。
我們知道,程式在結束的時候,系統會自動析構所有的全域性變數。事實上,系統也會析構所有的類的靜態成員變數,就像這些靜態成員也是全域性變數一樣。利用這個特徵,我們可以在單例類中定義一個這樣的靜態成員變數,而它的唯一工作就是在解構函式中刪除單例類的例項。如下面的程式碼中的CGarbo類(Garbo意為垃圾工人):
class CSingleton
{
//其他成員
public:
static CSingleton* GetInstance();
private:
CSingleton(){};
static CSingleton * m_pInstance;
class CGarbo //它的唯一工作就是在解構函式中刪除CSingleton的例項
{
public:
~CGarbo()
{
if( CSingleton::m_pInstance )
delete CSingleton::m_pInstance;
}
}
Static CGabor Garbo; //定義一個靜態成員,程式結束時,系統會自動呼叫它的解構函式
};
類CGarbo被定義為CSingleton的私有內嵌類,以防該類被在其他地方濫用。
程式執行結束時,系統會呼叫CSingleton的靜態成員Garbo的解構函式,該解構函式會刪除單例的唯一例項。
使用這種方法釋放單例物件有以下特徵:
在單例類內部定義專有的巢狀類;
在單例類內定義私有的專門用於釋放的靜態成員;
利用程式在結束時析構全域性變數的特性,選擇最終的釋放時機;
使用單例的程式碼不需要任何操作,不必關心物件的釋放。
具體程式碼如下:
#include <iostream>>
using namespace std;
class Singleton
{
public:
static Singleton *GetInstance();
private:
Singleton()
{
cout << "Singleton ctor" << endl;
}
~Singleton()
{
cout << "Singleton dtor" << endl;
}
static Singleton *m_pInstance;
class Garbo
{
public:
~Garbo()
{
if (Singleton::m_pInstance)
{
cout << "Garbo dtor" << endl;
delete Singleton::m_pInstance;
}
}
};
static Garbo garbo;
};
Singleton::Garbo Singleton::garbo; // 一定要初始化,不然程式結束時不會析構garbo
Singleton *Singleton::m_pInstance = NULL;
Singleton *Singleton::GetInstance()
{
if (m_pInstance == NULL)
m_pInstance = new Singleton;
return m_pInstance;
}
int main()
{
Singleton *p1 = Singleton::GetInstance();
Singleton *p2 = Singleton::GetInstance();
if (p1 == p2)
cout << "p1 == p2" << endl;
return 0;
}
輸出結果如下:
Singleton ctor
p1 == p2
Garbo dtor
Singleton dtor