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是我本身定义的释放宏。线程

  文章如有不妥,请你们指教。指针

相关文章
相关标签/搜索