单例模式:要求类只有一个对象实例,数据库连接池、线程池以及Windows任务管理器都是单例模式的应用。
那么如何去实现一个单例模式呢?C++中有5种实现的方式,首先从最简单说起
常规写法
class Singleton{
public:
static Singleton* getInstance()
{
if(_instance == nullptr)
_instance = new Singleton();
return _instance;
}
private:
Singleton() = default;
Singleton* _instance;
};
单线程种此写法没有任何问题,但是不适用多线程环境。 假如有两个线程A和线程B:
线程A先获得执行权,执行Singleton的getInstance获取实例_instance。发现_instance == nullptr,
则线程A开始准备执行new Singleton()操作。该操作细分为三步:
但是在多线程环境中,A线程可能会在即将执行这三布之前被挂起,线程B获得cpu的执行权,这就导致 线程B中_instance仍旧为nullptr,B执行new Singleton()操作。B执行完成后CPU执行权返回给A,A继续执行,A会继续执行new Singleton()
#include
using namespace std;
mutex mt;
class Singleton {
private:
static Singleton* _instance;
Singleton() {}
public:
static Singleton* getInstance() {
mt.lock(); // 加锁
if (_instance == nullptr)
_instance = new Singleton();
mt.unlock(); // 解锁
return _instance;
}
};
Singleton* Singleton::_instance = nullptr;
虽然加锁可以解决多线程下多次创建_instance的问题,但是每执行getInstance函数都需要进行加锁判断,消耗资源
#include
using namespace std;
mutex mt;
class Singleton {
private:
static Singleton* _instance;
Singleton() {}
public:
static Singleton* getInstance() {
if (_instance == nullptr) {
mt.lock(); // 解锁
if (_instance == nullptr)
_instance = new Singleton();
mt.unlock(); // 加锁
}
return _instance;
}
};
如果实例已经创建,就不需要同步。相反开始同步线程 但还是有问题,如_instance = new Singleton();
这句的执行同样有三步操作
在实际编译器执行中,这三步并不是严格按照1、2、3顺序执行,而是可能 发生其中某一步先执行的情况。 如执行顺序为:1->3->2,这样就造成线程不安全 如: 线程A执行实例化操作,但是在执行完1、2步骤的时候意外挂起,此时线程B开始执行。由于_instance指向了一块空间区域,所以其不为空,则线程B不执行实例话操作,而
_instance执行的内存区域并没有对象!
class Singleton {
public:
static Singleton& getInstance() {
static Singleton value;
return value;
}
private:
Singleton() = default;
Singleton(const Singleton& other) = delete;
Singleton& operator = (const Singleton&) = delete;
};
引用C++11的特性和局部static只初始化一次的特性。但是需要禁用拷贝构造函数和拷贝赋值运算
#include
#include
once_flag flag;
class Singleton {
public:
static Singleton& getInstance() {
call_once(flag, []() {_instance.reset(new Singleton())});
return *_instance;
}
private:
static unique_ptr<Singleton> _instance;
Singleton() = default;
Singleton(const Singleton& other) = delete;
Singleton& operator = (const Singleton&) = delete;
};
unique_ptr<Singleton> Singleton::_instance;