Singleton单件模式
【单例类的定义】
class Singleton{
private: //把构造函数设置成私有,让外界不能创建它
Singleton();
Singleton(const Singleton& other);
static Singleton* m_instance;
public:
static Singleton* getInstance();
};
Singleton* Singleton::m_instance=nullptr;
版本一:线程非安全¶
//[版本一] 线程非安全版本
Singleton* Singleton::getInstance() {
if (m_instance == nullptr) { //语句一
m_instance = new Singleton(); //语句二
}
return m_instance;
}
/*
假设对象还没有创建,m_instance现在为nullptr
线程A、线程B两个一起进入语句二,一起执行语句二
所以会导致,这个对象被创建多次,而真正被释放的只有一个
*/
版本二:线程安全¶
Singleton* Singleton::getInstance() {
Lock lock; //加锁
if (m_instance == nullptr) { //读操作
m_instance = new Singleton(); //写操作
}
return m_instance; //读操作
} //退出以后,锁lock被释放,别的线程才能执行函数
/*
只有写操作需要上锁,读操作是不需要上锁的,但在这个例子中,读操作也被上锁了。
锁是有代价的,要等待别人完成,所以对读上锁,会造成浪费
因此,在这个案例中,锁的代价过高。如果在高并发的场景下,这个代价是很高的
*/
版本三:线程安全,并双检查锁¶
//[版本三] 双检查锁(double check lock),但由于内存读写reorder不安全
Singleton* Singleton::getInstance() {
if(m_instance==nullptr){ //是否空
Lock lock; //空才加锁
if (m_instance == nullptr) {
/*加完锁之后,还需要判断是否为空
m_instance == nullptr判断是必要的!可以停下来想想为什么是必要的
其实如果没有这句,执行情况和版本二是一样的,也会被创建两次
*/
m_instance = new Singleton();
}
}
return m_instance;
}
版本四:线程安全,跨平台¶
//C++ 11版本之后的跨平台实现 (volatile)
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;
Singleton* Singleton::getInstance() {
Singleton* tmp = m_instance.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);//获取内存fence
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(m_mutex);
tmp = m_instance.load(std::memory_order_relaxed);
if (tmp == nullptr) {
tmp = new Singleton;
std::atomic_thread_fence(std::memory_order_release);//释放内存fence
m_instance.store(tmp, std::memory_order_relaxed);
}
}
return tmp;
}
版本五:线程安全(std::call_once)¶
#include<mutex> //std::call_once
//多线程安全
glal::ModelImporter* ModelImporter::getInstance()
{
static ModelImporter instance;
//只执行一次初始化函数
static std::once_flag oc;
std::call_once(oc, &ModelImporter::_init, &instance);
return &instance;
}
//初始化函数
void ModelImporter::_init()
{
//初始化操作...
}
AlgoFactory* AlgoFactory::getInstance()
{
static AlgoFactory instance;
static std::once_flag oc;
std::call_once(oc, []()
{
//加载插件
int successSize = dan::SGPluginManager::instance()->loadPluginsByFolder("", dan::StringList() << "glal.algo.provider.*.dll");
});
return &instance;
}