C++程序员们,快来写简洁的单例模式吧
作者:网络转载 发布时间:[ 2015/1/13 13:51:49 ] 推荐标签:C++ 程序员 net
想必每一位程序员都对设计模式中的单例模式非常的熟悉吧,以往我们用C++实现一个单例模式需要写以下代码:
1 class CSingleton
2 {
3 private:
4 CSingleton() //构造函数是私有的
5 {
6 }
7 static CSingleton *m_pInstance;
8 public:
9 static CSingleton * GetInstance()
10 {
11 if (m_pInstance == NULL) //判断是否第一次调用
12 m_pInstance = new CSingleton();
13 return m_pInstance;
14 }
15 };
|
当然,这份代码在单线程环境下是正确无误的,但是当拿到多线程环境下时这份代码会出现race condition,因此为了能在多线程环境下实现单例模式,我们首先想到的是利用同步机制来正确的保护我们的shared data,于是在多线程环境下单例模式代码变成了下面这样:
1 class CSingleton
2 {
3 private:
4 CSingleton() //构造函数是私有的
5 {
6 }
7 static CSingleton *m_pInstance;
8 mutex mtx;
9 public:
10 static CSingleton * GetInstance()
11 {
12 mtx.lock();
13 if (m_pInstance == NULL) //判断是否第一次调用
14 m_pInstance = new CSingleton();
15 mtx.unlock();
16 return m_pInstance;
17 }
18 };
|
正确是正确了,问题是每次调用GetInstance函数都要进入临界区,尤其是在heavy contention情况下函数将会成为系统的性能瓶颈,我们伟大的程序员发现我们不必每次调用GetInstance函数时都去获取锁,只是在第一次new这个实例的时候才需要同步,所以伟大的程序员们发明了的DCL技法,即Double Check Lock,代码如下:
1 Widget* Widget::pInstance{ nullptr };
2 Widget* Widget::Instance() {
3 if (pInstance == nullptr) { // 1: first check
4 lock_guard<mutex> lock{ mutW };
5 if (pInstance == nullptr) { // 2: second check
6 pInstance = new Widget();
7 }
8 }
9 return pInstance;
10 }
|
曾今有一段时间,这段代码是被认为正确无误的,但是一群伟大的程序员们发现了其中的bug!并且联名上书表示这份代码是错误的。要解释其中为什么出现了错误,需要读者十分的熟悉memory model,这里我不详细的说明了,一句话是在这份代码中第三行代码:if (pInstance == nullptr)和第六行代码pInstance = new Widget();没有正确的同步,在某种情况下会出现new返回了地址赋值给pInstance变量而Widget此时还没有构造完全,当另一个线程随后运行到第三行时将不会进入if从而返回了不完全的实例对象给用户使用,造成了严重的错误。在C++11没有出来的时候,只能靠插入两个memory barrier来解决这个错误,但是C++11已经出现了好几年了,其中我认为重要的是引进了memory model,从此C++11也能识别线程这个概念了!
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11