Singleton: WebRTC中ThreadManager中的单例模式
1. 什么是单例模式:
旨在确保一个类只有一个实例,并提供全局访问点。
应用场景:需要一个全局唯一的实例,避免资源浪费。
2. 单例模式的实现:
- Lazy Initialization(懒汉式)(延迟初始化):是有在需要时才创建实例,一般是第一次访问时才初始化,为了避免线程安全问题,通常需要加锁;
- Eager Initialization(饿汉式)(立即初始化):在类加载时就创建实例,确保类一开始就有一个唯一实例,不需要考虑线程安全问题,但在类加载时就初始化可能会导致一些性能上的开销;
- 双重检查锁定(Double-Checked Locking):(与第一种模式的加锁模式一样)
注:单例模式的类的构造函数和析构函数一定是private的!!
举例:
第一种方式:(为了保证线程安全,需要对getInstance()方法加锁)
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
class Singleton {
private:
static Singleton *instance;
static std::mutex mtx; // 用于加锁
Singleton() {} // 私有构造函数!!
public:
static Singleton *getInstance() {
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mtx); // 加锁
if (instance == nullptr) {
instance = new Singleton();
}
}
return instance;
}
};
第二种方式:
// 在类加载时就初始化实例
Singleton* Singleton::instance = new Singleton();
class Singleton {
private:
static Singleton* instance;
Singleton() {} // 私有构造函数
public:
static Singleton* getInstance() {
return instance; // 直接返回实例
}
};
WebRTC中的单例模式:
class ThreadManager {
public:
static ThreadManager *Insance() {
static ThreadManager *const thread_manager = new ThreadManager();
return thtread_manager;
}
private:
ThreadManager() {
pthread_key_create(&key_, nullptr);
}
~ThreadManager() {}
};
这是典型的懒汉式(Lazy Singleton)实现,使用了【局部静态变量】的方式来确保单例实例的唯一性,并且保证线程安全。
局部静态变量:
- 作用域:只能在声明它的函数内部访问,不能在函数外部直接访问;
- 生命周期:它在程序的整个运行周期都存在(即它在函数第一次调用时被创建,在程序结束时被销毁,所以thread_manager_在程序退出时销毁,不会有内存泄露?)
- 初始化:只在第一次被调用时初始化,后续的调用都会使用已经初始化的值。
为什么局部静态变量的初始化是线程安全的:
【从C++11开始】,局部静态变量是线程安全的,C++11保证在多线程场景下,只有一个线程能够初始化这个静态变量,其他线程将等待该变量初始化完成后再访问它,【这是由编译器和操作系统实现确保的(内存屏障?std::atomic?)】。