目录

每次程序运行都要读config.ini,由生成的对象传入参数,但计算机读取IO缓慢,而且这些配置基本不会变化,如果每次运行程序都要重新new这个对象,会带来很多不必要的损耗。
那么就需要整个程序运行中有且只有一个全局的对象,这个需求点就是单例模式。
- #include
- #include
- using namespace std;
-
- //外部程序没有机会new这个class
- class Singleton {
- private:
- Singleton() {
- m_singer = nullptr;
- cout << "构造一个SIngleton" << endl;
- }
- public:
- static Singleton* getInstance() {
- if (m_singer == nullptr) {
- m_singer = new Singleton;
- }
- return m_singer;
- }
- private:
- static Singleton* m_singer;
- };
-
-
- Singleton* Singleton::m_singer = nullptr;//懒汉式:延迟加载
- //Singleton* Singleton::m_singer = new Singleton;//饿汉式
- //C++中构造函数是线程不安全的
- int main() {
- Singleton* p1 = Singleton::getInstance();
- Singleton* p2 = Singleton::getInstance();
- printf("%x,%x", p1, p2);
- return 0;
- }

上面的例子就是懒汉式单例。
但是如果这个单例是多线程,会出现什么问题?


假设线程1在运行到m_singer=null时时间片轮转完了,那么此时就会切换到线程2中。
此时线程2也会进入到m_singer=null 这个if语句块中,并创建一个Singleton。
此时线程2结束,切回线程1,线程1继续执行刚才的现场,又创建了一个Singleton!
那么如何解决这个问题,根据操作系统的知识,我们需要为互斥执行的语句创建临界区,并进行互斥访问。

饿汉式与懒汉式的区别在于,懒汉式是一种延迟加载的方式,刚开始赋值为null,直到加载的时候才创建对象;而饿汉式在一开始初始化的时候就创建了对象,分配了资源。
因为计算机进行I/O操作十分缓慢,因此延迟加载是一种提升性能的手段。有助于资源的合理使用。
集群。一台机器再强大,也不一定能抗住所有人的访问,所以可以用多台机器搭建一个集群。
- //回避多线程的安全问题
- #include
- #include
- #include
- using namespace std;
-
- class Singleton;
- static std::map
myMap = std::map(); -
- //懒汉,延迟加载
- class Singleton {
- private:
- Singleton() {
- m_singer = nullptr;
- cout << "单例正在创建" << endl;
- }
- public:
- static Singleton* getInstance() {
- //std::map
::iterator it = myMap.find(DEFAULT_KEY); - if (myMap.find(DEFAULT_KEY) != myMap.end()) {
- return myMap.find(DEFAULT_KEY)->second;
- }
- if (m_singer == nullptr) {
- m_singer = new Singleton;
- myMap[DEFAULT_KEY] = m_singer;
- }
- return m_singer;
- }
-
- private:
- static Singleton* m_singer;
- static string DEFAULT_KEY;
- };
-
- Singleton* Singleton::m_singer = nullptr;
- string Singleton::DEFAULT_KEY = "one";
-
- int main() {
- Singleton* p1 = Singleton::getInstance();
- Singleton* p2 = Singleton::getInstance();
- printf("p1=%x, p2=%x\n", p1, p2);
- return 0;
- }
如果我们对这个DEFAULT_KEY做一些事情,让它成为多例。
- #include
- #include
- #include
- #include
- using namespace std;
-
- //缓存实例个数
- const static int NUM_MAX = 5;
- class Singleton;
- static std::map<int, Singleton*>myMap = std::map<int, Singleton*>();
-
- //懒汉,延迟加载
- class Singleton {
- private:
- Singleton() {
- m_singer = nullptr;
- cout << "单例正在创建" << endl;
- }
- public:
- static Singleton* getInstance() {
- m_singer = myMap[m_InstanceCount];
-
- if (m_singer == nullptr) {
- m_singer = new Singleton;
- myMap[m_InstanceCount] = m_singer;
- }
- m_InstanceCount++;
- if (m_InstanceCount > NUM_MAX) {
- m_InstanceCount = 1;
- }
- return m_singer;
- }
-
- private:
- static Singleton* m_singer;
- static int m_InstanceCount;//存放实例个数
- };
-
- Singleton* Singleton::m_singer = nullptr;
- int Singleton::m_InstanceCount = 1;
-
- int main() {
- Singleton* p1 = Singleton::getInstance();
- Singleton* p2 = Singleton::getInstance();
- Singleton* p3 = Singleton::getInstance();
- Singleton* p4 = Singleton::getInstance();
- Singleton* p5 = Singleton::getInstance();
- printf("p1=%x, \np2=%x, \np3=%x, \np4=%x, \np5=%x, \n\n", p1, p2, p3, p4, p5);
- Singleton* p6 = Singleton::getInstance();
- Singleton* p7 = Singleton::getInstance();
- Singleton* p8 = Singleton::getInstance();
- Singleton* p9 = Singleton::getInstance();
- Singleton* p10 = Singleton::getInstance();
- printf("p6=%x, \np7=%x, \np8=%x, \np9=%x, \np10=%x, ", p6, p7, p8, p9, p10);
- return 0;
- }

代码中写了10个instance,但是实际上只有5个instance被创建。
在实际应用中,可能集群需要维护5个单例,以便多用户访问和使用。