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修飾, 可是這樣其其內部數據能夠被修改, 這樣在多線程的時候是很危險的。性能

  上面單例模式已是線程安全的, 可是有個問題, 這個單例被建立後如何釋放呢?第一種方法 在在類裏面增長一個靜態的函數用於釋放指針,這樣作在程序中咱們隨時能夠釋放單例指針。可是有時候咱們的單例指針要一直伴隨着進程結束,這個時候咱們就能夠採用第二種方法: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是我本身定義的釋放宏。線程

  文章如有不妥,請你們指教。指針

相關文章
相關標籤/搜索