单例设计模式共享数据分析、解决,call_once

第七节 单例设计模式共享数据分析、解决,call_once

在这里插入图片描述

1.设计模式

  • 程序灵活,维护起来可能方便,用设计模式理念写出来的代码很晦涩,但是别人接管、阅读代码都会很痛苦
  • 老外应付特别大的项目时,把项目的开发经验、模块划分经验,总结整理成设计模式
  • 中国零几年设计模式刚开始火时,总喜欢拿一个设计模式往上套,导致一个小小的项目总要加几个设计模式,本末倒置
  • 设计模式有其独特的优点,要活学活用,不要深陷其中,生搬硬套

2.单例设计模式:
整个项目中,有某个或者某些特殊的类,只能创建一个属于该类的对象。
单例类:只能生成一个对象。

3.单例设计模式共享数据分析、解决
面临问题:需要在自己创建的线程中来创建单例类的对象,这种线程可能不止一个。我们可能面临GetInstance()这种成员函数需要互斥。
可以在加锁前判断m_instance是否为空,否则每次调用Singelton::getInstance()都要加锁,十分影响效率。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <mutex>
using namespace std;
mutex myMutex;
//懒汉模式
class Singelton
{
public:
static Singelton * getInstance() {
//双重锁定 提高效率
if (instance == NULL) {
lock_guard<mutex> myLockGua(myMutex);
if (instance == NULL) {
instance = new Singelton;
}
}
return instance;
}
private:
Singelton() {}
static Singelton *instance;
};
Singelton * Singelton::instance = NULL;
//饿汉模式
class Singelton2 {
public:
static Singelton2* getInstance() {
return instance;
}
private:
Singelton2() {}
static Singelton2 * instance;
};
Singelton2 * Singelton2::instance = new Singelton2;
int main(void)
{
Singelton * singer = Singelton::getInstance();
Singelton * singer2 = Singelton::getInstance();
if (singer == singer2)
cout << "二者是同一个实例" << endl;
else
cout << "二者不是同一个实例" << endl;
cout << "---------- 以下 是 饿汉式 ------------" << endl;
Singelton2 * singer3 = Singelton2::getInstance();
Singelton2 * singer4 = Singelton2::getInstance();
if (singer3 == singer4)
cout << "二者是同一个实例" << endl;
else
cout << "二者不是同一个实例" << endl;
return 0;
}

如果觉得在单例模式new了一个对象,而没有自己delete掉,这样不合理。可以增加一个类中类CGarhuishou,new一个单例类时创建一个静态的CGarhuishou对象,这样在程序结束时会调用CGarhuishou的析构函数,释放掉new出来的单例对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Singelton
{
public:
static Singelton * getInstance() {
if (instance == NULL) {
static CGarhuishou huishou;
instance = new Singelton;
}
return instance;
}
class CGarhuishou {
public:
~CGarhuishou()
{
if (Singelton::instance)
{
delete Singelton::instance;
Singelton::instance = NULL;
}
}
};
private:
Singelton() {}
static Singelton *instance;
};
Singelton * Singelton::instance = NULL;

4.std::call_once():
函数模板,该函数的第一个参数为标记,第二个参数是一个函数名(如a())。
功能:能够保证函数a()只被调用一次。具备互斥量的能力,而且比互斥量消耗的资源更少,更高效。
call_once()需要与一个标记结合使用,这个标记为std::once_flag;其实once_flag是一个结构,call_once()就是通过标记来决定函数是否执行,调用成功后,就把标记设置为一种已调用状态。

多个线程同时执行时,一个线程会等待另一个线程先执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
once_flag g_flag;
class Singelton
{
public:
static void CreateInstance()//call_once保证其只被调用一次
{
instance = new Singelton;
}
//两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕
static Singelton * getInstance() {
call_once(g_flag, CreateInstance);
return instance;
}
private:
Singelton() {}
static Singelton *instance;
};
Singelton * Singelton::instance = NULL;