程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> c++單列模式與線程安全

c++單列模式與線程安全

編輯:C++入門知識

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修飾, 但是這樣其其內部數據可以被修改, 這樣在多線程的時候是很危險的。     上面單例模式已經是線程安全的, 但是有個問題, 這個單例被創建後如何釋放呢?第一種方法 在在類裡面增加一個靜態的函數用於釋放指針,這樣做在程序中我們隨時可以釋放單例指針。但是有時候我們的單例指針要一直伴隨著進程結束,這個時候我們就可以采用第二種方法:   復制代碼 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; }; 復制代碼  我們在類裡面添加了一個CGarbo類,這個類只有一個作用負責清除單列對象指針,定義一個static的Garbo對象, 該對象聲明周期與單例對象指針是一樣的,這個靜態Garbo對象也會在程序結束時釋放,這個時候會將單例指針所擁有資源也釋放掉。注意SAFE_DELETE是我自己定義的釋放宏

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved