记录学习C++的设计模式的足迹。

Singleton(单例)模式

Singleto要解决的问题是如何:整个程序只创建一个唯一的变量(对象)?
面向过程中(c),只需要创造唯一的全局变量,好的设计会用结构体等将其封装,以减少全局变量的暴露和冲突。
面向对象的中(c++),以类的形式实现的全局变量就被称为Singleton(单例)模式(全局唯一,修改可全局更新)。

线程安全

  单例对象在整个程序中只实例一次,之后访问该对象都通过它自身的接口。在多线程中,单例对象可能被同时访问,数据被同时修改,造成对数据的不一致性。因此对单例数据需要实现用同步机制来保证各个线程安全访问。

共享资源同步机制

1.给共享的资源加把锁,保证每个资源变量每时每刻至多被一个线程占用。
2.让线程也拥有资源,不用去共享进程中的资源。

单例实现

  单例实现懒汉模式饥饿模式,它们区别在于实例的时间点不同,懒汉模式在需要时在创建,饿汉模式在程序开始执行时就创建。

  • 懒汉模式:以时间换空间,适应于访问量较小的共享数据。
  • 饿汉模式:以空间换时间,适应于访问量较大的共享数据,或者线程比较多。

单例的特点

  • 1.构造函数和析构函数属性是private,可以禁止外部构造和析构。
  • 2.拷贝构造和赋值构造函数属性是private,可以禁止外部拷贝和赋值,保证实例的唯一性。
  • 3.类的成员中有获取实例的静态函数,外部可以通过该API全局访问。

懒汉模式

  系统运行中,单例的实例并不存在,当需要使用该单例实例时,会去创建并使用实例。多线程时可能同时创建,需要通过加锁的方式保证安全。

懒汉模式(加锁)

lock_lazy_singleton.hlink
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
#ifndef LOCK_LAZY_SINGLETON_H
#define LOCK_LAZY_SINGLETON_H

#include <iostream>
#include <mutex>

using namespace std;

class LockLazySingleton
{
public:
// Static Get myself instace point api.
static LockLazySingleton* GetInstace();

// The singleton variable.
string name_;
int age_;

private:
// Private constructor and destructor.
LockLazySingleton();
virtual ~LockLazySingleton();

// Private copy constructor and assignment operator.
LockLazySingleton(const LockLazySingleton&);
LockLazySingleton& operator=(const LockLazySingleton&);

// Static myself instance point.
static LockLazySingleton *m_instanceSingleton;
// Static lock to protect the object.
static std::mutex mtx;

};

#endif // LAZY_SINGLETON_H
lock_lazy_singleton.cpplink
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
#include "lock_lazy_singleton.h"

// LazySingleton* LazySingleton::m_instanceSingleton = 0;
LockLazySingleton* LockLazySingleton::m_instanceSingleton = nullptr;
std::mutex LockLazySingleton::mtx;

LockLazySingleton::LockLazySingleton()
{
std::cout << "Create LockLazySingleton" << std::endl;
}

LockLazySingleton::~LockLazySingleton()
{

}

LockLazySingleton* LockLazySingleton::GetInstace()
{
if (m_instanceSingleton == NULL) {
mtx.lock();
// If the Singleton not null, then less mutex lock time.
if (m_instanceSingleton == NULL) {
m_instanceSingleton = new LockLazySingleton;
}
mtx.unlock();
}
return m_instanceSingleton;
}

懒汉模式(局部成员)

unlock_lazy_singleton.hlink
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
#ifndef UNLOCK_LAZY_SINGLETON_H
#define UNLOCK_LAZY_SINGLETON_H

#include <iostream>
#include <mutex>

// The unlock LazySinglenton just support c++11.

using namespace std;

class UnlockLazySingleton
{
public:
static UnlockLazySingleton& GetInstace();
string name_;
int age_;

private:
// Private constructor and destructor.
UnlockLazySingleton();
virtual ~UnlockLazySingleton();

// Private copy constructor and assignment operator.
UnlockLazySingleton(const UnlockLazySingleton&);
UnlockLazySingleton& operator=(const UnlockLazySingleton&);
};

#endif // UNLOCK_LAZY_SINGLETON_H
unlock_lazy_singleton.cpplink
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "unlock_lazy_singleton.h"

UnlockLazySingleton::UnlockLazySingleton()
{
std::cout << "Create UnlockLazySingleton." << std::endl;
}

UnlockLazySingleton::~UnlockLazySingleton()
{

}

UnlockLazySingleton& UnlockLazySingleton:: GetInstace()
{
static UnlockLazySingleton unlock_lazy_singleton;
return unlock_lazy_singleton;
}

饿汉模式

  程序一执行,就初始化创建单例实例,之后直接调用。

hunger_singleton.hlink
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
#ifndef HUNGER_SINGLETON_H
#define HUNGER_SINGLETON_H

#include <iostream>

using namespace std;

class HungerSingleton
{
public:
static HungerSingleton* GetInstace();

string name_;
int age_;

private:
// Private constructor and destructor.
HungerSingleton();
virtual ~HungerSingleton();

// Private copy constructor and assignment operator.
HungerSingleton(const HungerSingleton&);
HungerSingleton& operator=(const HungerSingleton&);

// Static point myself.
static HungerSingleton *m_instanceSingleton;
};

#endif // HUNGER_SINGLETON_H
hunger_singleton.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "hunger_singleton.h"

HungerSingleton* HungerSingleton::m_instanceSingleton = new HungerSingleton;

HungerSingleton::HungerSingleton()
{

}

HungerSingleton::~HungerSingleton()
{

}

HungerSingleton* HungerSingleton::GetInstace()
{
return m_instanceSingleton;
}

调用方法

main.cpplink
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
#include <iostream>
#include "lock_lazy_singleton.h"
#include "unlock_lazy_singleton.h"
#include "hunger_singleton.h"

using namespace std;

void ShowLockLazySingleton()
{
LockLazySingleton *lock_lazy_singleton = LockLazySingleton::GetInstace();
cout << lock_lazy_singleton->name_ << endl;
cout << lock_lazy_singleton->age_ << endl;

}

void ShowUnLockLazySingleton()
{
cout << UnlockLazySingleton::GetInstace().name_ << endl;
cout << UnlockLazySingleton::GetInstace().age_ << endl;

}

void ShowHungerSingleton()
{
HungerSingleton* hunger_singleton = HungerSingleton::GetInstace();
cout << hunger_singleton->name_ << endl;
cout << hunger_singleton->age_ << endl;
}

int main()
{
// Set the Singleton variable.
LockLazySingleton *lock_lazy_singleton = LockLazySingleton::GetInstace();
lock_lazy_singleton->name_ = "xiao ming";
lock_lazy_singleton->age_ = 24;

UnlockLazySingleton::GetInstace().name_ = "xiao hong";
UnlockLazySingleton::GetInstace().age_ = 22;

HungerSingleton* hunger_singleton = HungerSingleton::GetInstace();
hunger_singleton->name_ = "xiao gang";
hunger_singleton->age_ = 23;

ShowLockLazySingleton();
ShowUnLockLazySingleton();
ShowHungerSingleton();

hunger_singleton->name_ = "xiao hua";
hunger_singleton->age_ = 25;

ShowHungerSingleton();

return 0;
}