-
懒汉模式存在线程不安全,解决方法是:加互斥锁
#include<iostream>
#include<thread>//C++11的线程库
#include<mutex>//互斥锁
using namespace std;
std::mutex mtx;//全局的互斥锁
class Object
{
private:
int value;
static Object* pobj;
private:
Object(int x = 0) :value(x) { cout << "create object" << endl; }//让其在外部不能创建对象
public:
Object(const Object&) = delete;//删除拷贝构造,防止对象通过拷贝构造创建对象
Object& operator=(const Object&) = delete;//删除赋值,防止简单类型通过赋值创建对象
public:
~Object() { cout << "destroy object" << endl; }//防止某些情况不能正常释放
//void SetValue(Object* const this,int x=0)
void SetValue(int x = 0) { value = x; }
//int GetValue(const Object* const this)
int GetValue() const { return value; }
static Object& GetRefObject()//获取实例的静态方法
{
mtx.lock();//创建对象前加锁,保证只有一个线程进行创建对象且仅创建一次
if (nullptr == pobj)//线程判断是否已经创建过对象,如果已经创建则不再创建
{
pobj = new Object(10);
}
mtx.unlock();//创建完成时解锁
return *pobj;
}
};
Object* Object::pobj = nullptr;
void funa()
{
Object& obja = Object::GetRefObject();
obja.SetValue(100);
cout << "&obja " << &obja << endl;
}
void funb()
{
Object& objb = Object::GetRefObject();
cout << objb.GetValue() << endl;
cout << "&objb " << &objb << endl;
}
int main()
{
std::thread tha(funa);
std::thread thb(funb);
tha.join();//等待线程结束
thb.join();//等待线程结束
}
加锁后保证了线程安全,对象仅被创建了一次(obja和objb是同一个地址,Object构造函数只调用一次),线程funa设置的value值未被覆盖。运行结果如下
-
懒汉模式更安全的解决方法是双重锁机制(加锁和if双重判断)
原因:
第一层的if:new出第一个实例后,后面每个线程访问到最外面的if判断,如果已经创建过对象就直接返回了,没有加锁的开销
第二层If,:判断类对象指针为空,才进行实例
[锁机制]:保证同一时刻只有一个线程访问(即进行实例化)
#include<iostream>
#include<thread>//C++11的线程库
#include<mutex>//互斥锁
using namespace std;
std::mutex mtx;//全局的互斥锁
class Object
{
private:
int value;
static Object* pobj;
private:
Object(int x = 0) :value(x) { cout << "create object" << endl; }//让其在外部不能创建对象
public:
Object(const Object&) = delete;//删除拷贝构造,防止对象通过拷贝构造创建对象
Object& operator=(const Object&) = delete;//删除赋值,防止简单类型通过赋值创建对象
public:
~Object() { cout << "destroy object" << endl; }//防止某些情况不能正常释放
//void SetValue(Object* const this,int x=0)
void SetValue(int x = 0) { value = x; }
//int GetValue(const Object* const this)
int GetValue() const { return value; }
static Object& GetRefObject()//获取实例的静态方法
{
if (nullptr == pobj)//先进行判断,如果pobj不为空(即已经创建过对象),则线程直接跳过这一块域,减少加锁开销
{
mtx.lock();//创建前加锁,防止其他线程进行二次创建
if (nullptr == pobj)//线程判断是否已经创建过对象,保证单例模式创建对象唯一性
{
pobj = new Object(10);
}
mtx.unlock();//创建完成时解锁
}
return *pobj;
}
};
Object* Object::pobj = nullptr;
void funa()
{
Object& obja = Object::GetRefObject();
obja.SetValue(100);
cout << "&obja " << &obja << endl;
}
void funb()
{
Object& objb = Object::GetRefObject();
cout << objb.GetValue() << endl;
cout << "&objb " << &objb << endl;
}
int main()
{
std::thread tha(funa);
std::thread thb(funb);
tha.join();//等待线程结束
thb.join();//等待线程结束
}