一般c++裏面的單列模式很容易實現,咱們也不須要去考慮其線程安全的問題,可是在多線程環境中咱們卻必需要考慮到。首先咱們來分析下一下的這個單列模式爲何不是線程安全的,一般的單列模式寫法:c++
class MsgOfArrival { public: ~MsgOfArrival(void); MAP_STRING_PNORMALMSGCOLLECTION m_normalmsgMap; static MsgOfArrival* GetInstance(); private: MsgOfArrival(void); static MsgOfArrival* m_pInstance; }; MsgOfArrival* MsgOfArrival::m_pInstance = NULL; MsgOfArrival::MsgOfArrival(void) { } MsgOfArrival::~MsgOfArrival(void) { }
假設兩個多線程同時執行GetInstance()函數,那麼m_pInstance==NULL時, 兩個線程同時進入了if中時就會建立兩個指針,這固然是不行的。解決這個問題首先咱們會想到加鎖,如改爲
MsgOfArrival* MsgOfArrival::GetInstance() { if (m_pInstance == NULL) { EnterCriticalSection(&g_cs); m_pInstance = new MsgOfArrival;
LeaveCriticalSection(&g_cs)
}
return m_pInstance;
}
這樣固然能夠,並且m_pInstance一但new成功,GetInstance調用不會在進入if中,因此大量調用該單列並不會由於臨界區形成性能瓶頸。安全
第二種方法是靜態變量初始化的時候,咱們直接讓其new一個指針,由於咱們知道靜態變量是在Main函數還沒執行的時候就由主線程完成了初始化,既然單例指針還沒進入到main就已經構造了, 那麼咱們固然不須要在進入main之後的多線程中來擔憂單例構造的線程安全性。代碼以下:多線程
class MsgOfArrival { public: ~MsgOfArrival(void); MAP_STRING_PNORMALMSGCOLLECTION m_normalmsgMap; static const MsgOfArrival* GetInstance(); private: MsgOfArrival(void); static const MsgOfArrival* m_pInstance; }; const MsgOfArrival* MsgOfArrival::m_pInstance = new MsgOfArrival; MsgOfArrival::MsgOfArrival(void) { } MsgOfArrival::~MsgOfArrival(void) { } const MsgOfArrival* MsgOfArrival::GetInstance() { return m_pInstance; }
須要注意m_pInstance使用const進行修飾的,其所指對象是const的也就是說咱們不能修改這個單列對象,這也要求咱們在調用改單列的函數時該函數也必須是const的如:函數
int getdata() const; //函數聲明 //函數定義 int MsgOfArrival::getdata() const { // // return m_nVal; }
固然m_pInstance也能夠不用const修飾, 可是這樣其其內部數據能夠被修改, 這樣在多線程的時候是很危險的。性能
上面單例模式已是線程安全的, 可是有個問題, 這個單例被建立後如何釋放呢?第一種方法 在在類裏面增長一個靜態的函數用於釋放指針,這樣作在程序中咱們隨時能夠釋放單例指針。可是有時候咱們的單例指針要一直伴隨着進程結束,這個時候咱們就能夠採用第二種方法:spa
class MsgOfArrival { public: ~MsgOfArrival(void); MAP_STRING_PNORMALMSGCOLLECTION m_normalmsgMap; static const MsgOfArrival* GetInstance(); private: class CGarbo { public: ~CGarbo() { SAFE_DELETE(MsgOfArrival::m_pInstance); } }; static CGarbo Garbo; //清理資源 MsgOfArrival(void); static const MsgOfArrival* m_pInstance; }; //注意靜態對象也必須想變量同樣初始化,不然這個靜態對象不存在,也就不會去執行析構函數 MsgOfArrival::CGarbo MsgOfArrival:: Garbo; //清理資源
咱們在類裏面添加了一個CGarbo類,這個類只有一個做用負責清除單列對象指針,定義一個static的Garbo對象, 該對象聲明週期與單例對象指針是同樣的,這個靜態Garbo對象也會在程序結束時釋放,這個時候會將單例指針所擁有資源也釋放掉。注意SAFE_DELETE是我本身定義的釋放宏。線程
文章如有不妥,請你們指教。指針