今天被问到单例模式了,之前没有很关注线程安全问题,结果悲剧了。这里主要有两个问题:
1) 加锁
2) 要粒度细,也就是说尽量锁最少的代码
所以我们必须加锁,而且只要锁住new就可以了,不要在if判断之前锁。但是这里有出现一个问题就是,如果我们仅仅锁住new的话,伪代码如下
testobj * getinstance()
{
if(m_instance ==NULL)
{
lock
m_instance = new testobj();
unlock
}
}
那么假如有两个线程(A和B)同时调用getinstance,两个都通过了if的判断,从而开始竞争锁,比如A先得到锁资源,那么m_instance 会被new出来,然后释放锁,接着B得到锁,接着又去new了一把,其实这个时候m_instance已经存在了,不用new了。所以我们要用double check
另外对m_instance的初始化时单例模式很重要的一个部分
#include <stdio.h>
#include <pthread.h>class CLocks{
private:
pthread_mutex_t m_mutex;
public:
CLocks()
{
pthread_mutex_init(&m_mutex,NULL);
}
~CLocks(){
pthread_mutex_destroy(&m_mutex);
}
void Lock(){ pthread_mutex_lock(&m_mutex);}
void UnLock() { pthread_mutex_unlock(&m_mutex); }
};
class A{
private:
static A * m_instance;
A(){}
A(A&){}
A& operator=(const A&);
static CLocks m_lock;
public:
static A* getinstance()
{
if(m_instance == NULL)
{
m_lock.Lock();
//两次m_instance的判断为,double check,防止被new多次
if(m_instance == NULL)
{
m_instance = new A();
}
m_lock.UnLock();
}
return m_instance;
}
};
//初始化很重要的啊
CLocks A::m_lock;
A* A::m_instance = NULL;
int main( )
{
A * pa = A::getinstance();
return 0;
}
C++完美实现Singleton模式 http://www.cppblog.com/dyj057/archive/2005/09/20/346.aspx 写得很好的一篇文章