一、饿汉版本(本身就是线程安全)
#include <iostream>
using namespace std;
class Singleton
{
public:
static Singleton* getIns()
{
return pIns;
}
private:
Singleton() {};
~Singleton() {};
static Singleton* pIns;
};
Singleton* Singleton::pIns = new (std::nothrow) Singleton;
int main()
{
Singleton* ps1 = Singleton::getIns();
Singleton* ps2 = Singleton::getIns();
if (ps1 == ps2)
{
cout << "ps1 == ps2" << endl;
}
else
{
cout << "error" << endl;
}
return 0;
}
二、懒汉非线程安全版本
#include <iostream>
#include <vector>
using namespace std;
class Singleton
{
public:
static Singleton* get_ins()
{
if (_ins == nullptr) _ins = new Singleton;
return _ins;
}
private:
static Singleton* _ins;
private:
Singleton() {}
~Singleton() {}
Singleton(const Singleton& another) {}
Singleton& operator=(const Singleton& another) {}
};
Singleton* Singleton::_ins = nullptr;
int main()
{
Singleton* ps = Singleton::get_ins();
Singleton* ps2 = Singleton::get_ins();
if (ps == ps2) cout << "ps == ps2" << endl;
else cout << "ps != ps2" << endl;
return 0;
}
三、懒汉多线程加锁版本(性能不高)
#include <iostream>
using namespace std;
mutex mtx;
class Singleton
{
public:
static Singleton* getIns()
{
unique_lock<mutex> ul(mtx);
if (pIns == nullptr) pIns = new Singleton;
return pIns;
}
private:
Singleton() {};
~Singleton() {};
static Singleton* pIns;
};
Singleton* Singleton::pIns = nullptr;
int main()
{
Singleton* ps1 = Singleton::getIns();
Singleton* ps2 = Singleton::getIns();
if (ps1 == ps2)
{
cout << "ps1 == ps2" << endl;
}
}
这种写法不会出现上面两个线程A和B都执行到p=nullptr
里面的情况,当线程A在执行p = new Singleton()的时候,线程B如果调用了instance(),一定会被阻塞在加锁处,等待线程A执行结束后释放这个锁。从而是线程安全的。
但是这种写法性能非常低下,因为每次调用instance()都会加锁释放锁,而这个步骤只有在第一次new Singleton()才是有必要的,只要p被创建出来了,不管多少线程同时访问,使用if (p == nullptr)进行判断都是足够的(只是读操作,不需要加锁),没有线程安全问题,加了锁之后反而存在性能问题。
因此引出双重检查锁。
四、双重检查锁
#include <iostream>
using namespace std;
mutex mtx;
class Singleton
{
public:
class CGarbo
{
public:
~CGarbo()
{
if (Singleton::pIns != nullptr)
{
delete Singleton::pIns;
}
}
};
static CGarbo cg;
static Singleton* getIns()
{
if (pIns == nullptr)
{
unique_lock<mutex> ul(mtx);
if (pIns == nullptr)
{
pIns = new Singleton; // 指令乱序的本质
}
}
return pIns;
}
private:
Singleton() {};
~Singleton() {};
static Singleton* pIns;
};
Singleton* Singleton::pIns = nullptr;
Singleton::CGarbo cg;
int main()
{
Singleton* ps1 = Singleton::getIns();
Singleton* ps2 = Singleton::getIns();
if (ps1 == ps2)
{
cout << "ps1 == ps2" << endl;
}
}
可能会发生指令乱序的问题。
五、最推荐的懒汉式单例
(magic static )——局部静态变量
#include <iostream>
using namespace std;
class Singleton
{
public:
static Singleton& get_ins()
{
static Singleton _ins;
return _ins;
}
private:
Singleton() {}
~Singleton() {}
Singleton(const Singleton& another) {}
Singleton& operator=(const Singleton& another) {}
};
int main()
{
Singleton& ps = Singleton::get_ins();
Singleton& ps2 = Singleton::get_ins();
if (&ps == &ps2) cout << "ps == ps2" << endl;
else cout << "ps != ps2" << endl;
return 0;
}
#include <iostream>
using namespace std;
class Singleton
{
public:
static Singleton* getIns()
{
static Singleton ins;
return &ins;
}
private:
Singleton() {};
~Singleton() {};
};
int main()
{
Singleton* ps1 = Singleton::getIns();
Singleton* ps2 = Singleton::getIns();
if (ps1 == ps2)
{
cout << "ps1 == ps2" << endl;
}
return 0;
}