1 本篇主要讨论下多线程下的单例模式实现:

  首先是 double check 实现方式: 这种模式可以满足多线程环境下,只产生一个实例。

  1. template<typename T>
  2. class dclsingleton
  3. {
  4. public:
  5. static T& GetInstance()
  6. {
  7. if(NULL == value_)
  8. {
  9. MutexGuard mg(mutex_);
  10. if (NULL == value_)
  11. {
  12. value_ = new T;
  13. }
  14. }
  15.  
  16. return *value_;
  17. }
  18. protected:
  19. dclsingleton() { std::cout << "dclsingleton constuctor called" << std::endl; }
  20. dclsingleton(const dclsingleton &dcl) {}
  21.  
  22. private:
  23. static T* value_;
  24. static Mutex mutex_;
  25. };

  但是这种实现存在除bug的隐患, 问题就在: value_ = new T; 上。《程序员的自我修养》上指出:

  这样的代码是有问题的,问题的来源在于 cpu 的乱序执行。c++里的new 包含了两步。

  (1)分配内存

  (2)调用构造函数

  所以 value_ = new T;  实际上包含了三步:

  (1)分配内存

  (2)在分配内存的位置上调用构造函数  

  (3)将内存地址赋值给 value_;

  这三步中,(2), (3)两步是可以颠倒的,也就是说,可能出现,先执行(3)这是 value_已经不为NULL, 当出现另一个对GetInstance的并发调用,if 内的 value_ != NULL于是返回,但是还没有调用构造函数。于是使用这个指针的时候,就会导致崩溃。

  这时候需要保证(2), (3)的执行顺序,通常需要加上内存屏障,保证一定保证(2)执行完以后,再执行(3)

  这里我加上了__sync_synchronize(); 后 实现是这样的:

  

  1.        static T& GetInstance()
  2. {
  3. if(NULL == value_)
  4. {
  5. MutexGuard mg(mutex_);
  6. if (NULL == value_)
  7. {
  8. T* tmp = static_cast<T*>(operator new (sizeof(T)));
  9. new (tmp) T();
  10. __sync_synchronize();
  11. value_ = tmp;
  12. }
  13. }
  14.  
  15. return *value_;
  16. }

    这样便可以既保证多线程环境安全,又保证不会出现上面的问题。

2. 加上内存屏障的示例代码:dcl_single.h

  

  1. #ifndef __DCL_SINGLE_H
  2. #define __DCL_SINGLE_H
  3.  
  4. #include <iostream>
  5.  
  6. namespace yl
  7. {
  8. class Mutex
  9. {
  10. public:
  11. Mutex()
  12. {
  13. pthread_mutex_init(&mutex_, NULL);
  14. }
  15. ~Mutex()
  16. {
  17. pthread_mutex_destroy(&mutex_);
  18. }
  19.  
  20. public:
  21. void Lock()
  22. {
  23. pthread_mutex_lock(&mutex_);
  24. }
  25. void UnLock()
  26. {
  27. pthread_mutex_unlock(&mutex_);
  28. }
  29.  
  30. private:
  31. pthread_mutex_t mutex_;
  32. };
  33.  
  34. class MutexGuard
  35. {
  36. public:
  37. MutexGuard(Mutex& m) : mutex_(m)
  38. {
  39. mutex_.Lock();
  40. }
  41.  
  42. ~MutexGuard()
  43. {
  44. mutex_.UnLock();
  45. }
  46.  
  47. private:
  48. Mutex mutex_;
  49. };
  50.  
  51. template<typename T>
  52. class dclsingleton
  53. {
  54. public:
  55. static T& GetInstance()
  56. {
  57. if(NULL == value_)
  58. {
  59. MutexGuard mg(mutex_);
  60. if (NULL == value_)
  61. {
  62. T* tmp = static_cast<T*>(operator new (sizeof(T)));
  63. new (tmp) T();
  64. __sync_synchronize();
  65. value_ = tmp;
  66. }
  67. }
  68.  
  69. return *value_;
  70. }
  71. protected:
  72. dclsingleton() { std::cout << "dclsingleton constuctor called" << std::endl; }
  73. dclsingleton(const dclsingleton &dcl) {}
  74.  
  75. private:
  76. static T* value_;
  77. static Mutex mutex_;
  78. };
  79.  
  80. template<typename T>
  81. T* dclsingleton<T>::value_ = NULL;
  82.  
  83. template<typename T>
  84. Mutex dclsingleton<T>::mutex_;
  85. }
  86.  
  87. #endif

  singletonTest.cpp

  1. #include "dcl_single.h"
  2. #include <iostream>
  3.  
  4. namespace yl
  5. {
  6. class MgrSg : public dclsingleton<MgrSg>
  7. {
  8.  
  9. private:
  10. friend class dclsingleton <MgrSg>;
  11. MgrSg(){ std::cout << "MgrSg: constructor called" << std::endl; }
  12. ~MgrSg() { std::cout << "MgrSg: desconstructor called" << std::endl; }
  13. public:
  14. void print()
  15. {
  16. std::cout << "print called" << std::endl;
  17. }
  18. };
  19. }
  20.  
  21. int
  22. main(void)
  23. {
  24. using namespace yl;
  25.  
  26. MgrSg::GetInstance().print();
  27. return ;
  28. }

3. 还可以用 unix 下的 pthread_once 来实现单例模式:

  

  1. template <typename T>
  2. class MySingleton
  3. {
  4. public:
  5. static T & getInstance()
  6. {
  7. pthread_once(&ponce_, &MySingleton::init);
  8. return *instance;
  9. }
  10.  
  11. protected:
  12. MySingleton() {}
  13. MySingleton(const MySingleton&) {}
  14. private:
  15. static void init()
  16. {
  17. instance = new T();
  18. }
  19. private:
  20. static pthread_once_t ponce_;
  21. static T *instance;
  22. };
  23.  
  24. template<typename T>
  25. pthread_once_t MySingleton<T>::ponce_ = PTHREAD_ONCE_INIT;
  26.  
  27. template<typename T>
  28. T *MySingleton<T>::instance = nullptr;
  29. }

4.我自己遇到的就是以上两种情况,若是希望了解更全面,可参考下边:

  http://www.cnblogs.com/liyuan989/p/4264889.html

5. 水平有限,望及时指出错误。谢谢

  

c++之单例模式的更多相关文章

  1. C++实现线程安全的单例模式

    在某些应用环境下面,一个类只允许有一个实例,这就是著名的单例模式.单例模式分为懒汉模式,跟饿汉模式两种. 首先给出饿汉模式的实现 template <class T> class sing ...

  2. 23种设计模式--单例模式-Singleton

    一.单例模式的介绍 单例模式简单说就是掌握系统的至高点,在程序中只实例化一次,这样就是单例模式,在系统比如说你是该系统的登录的第多少人,还有数据库的连接池等地方会使用,单例模式是最简单,最常用的模式之 ...

  3. angular2系列教程(十)两种启动方法、两个路由服务、引用类型和单例模式的妙用

    今天我们要讲的是ng2的路由系统. 例子

  4. java设计模式之--单例模式

    前言:最近看完<java多线程编程核心技术>一书后,对第六章的单例模式和多线程这章颇有兴趣,我知道我看完书还是记不住多少的,写篇博客记录自己所学的只是还是很有必要的,学习贵在坚持. 单例模 ...

  5. 设计模式C#合集--单例模式

    单例模式 代码: 第一种: private static Singleton singleton = null; private Singleton() { } public static Singl ...

  6. 设计模式之单例模式(Singleton)

    设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...

  7. GOF23设计模式之单例模式

    ·核心作用: -保证一个类只有一个实例,并且提供一个访问该实例的全局访问点. ·常见应用场景: -Windows的Task Manager(任务管理器)就是很典型的单例模式 -Windows的Recy ...

  8. GJM : C#设计模式(1)——单例模式

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  9. PHP设计模式(四)单例模式(Singleton For PHP)

    今天讲单例设计模式,这种设计模式和工厂模式一样,用的非常非常多,同时单例模式比较容易的一种设计模式. 一.什么是单例设计模式 单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对 ...

  10. java设计模式之单例模式(几种写法及比较)

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

随机推荐

  1. python一两行代码完成的骚操作

    分享一个前几天晚上粉丝问的问题,觉得很实用的一个问题,用python读取Excel并保存字典,如何做? 下面是该同学问题截图和代码 ​ 代码截图是下面这样的 ​ 不知道大家第一眼看了这个代码,什么感受 ...

  2. 前端 javascript 数据类型 字符串

    字符串是由字符组成的数组,但在JavaScript中字符串是不可变的:可以访问字符串任意位置的文本,但是JavaScript并未提供修改已知字符串内容的方法. obj.charAt(n) 返回字符串中 ...

  3. Apache Lucene初探

    讲解之前,先来分享一些资料 首先,学习任何一门新的亦或是旧的开源技术,百度其中一二是最简单的办法,先了解其中的大概,思想等等.这里就贡献一个讲解很到位的ppt 这是Lucene4.0的官网文档:htt ...

  4. go-009-函数

    一.概述 Go 语言最少有个 main() 函数. 你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务. 函数声明告诉了编译器函数的名称,返回类型,和参数. Go 语言标准库提供了多种可动 ...

  5. composer是php包管理工具

    composer是 PHP 用来管理依赖(dependency)关系的工具.你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer 会帮你安装这些依赖的库文件. MAC.L ...

  6. ASP.NET的优点

    ASP.NET 是一个统一的 Web 开发平台,它提供开发人员创建企业级 Web 应用程序所需的服务.尽管 ASP.NET 的语法基本上与 ASP 兼容,但是它还提供了一个新的编程模型和基础结构以提高 ...

  7. Avocado 安装和简单测试

    1.Avocado 安装 1.1 通过包安装 像Fedora可以通过rpm包进行安装,其他通过RPM管理的发行版需要自己制作相关包.Avocado同样支持DEP包的安装可以在contrib/packa ...

  8. vim高亮显示文本

    行列高亮设置 • 行高亮 " 设置高亮行的颜色,ctermbg设定背景色,ctermfg设定前景色 set cursorline hi CursorLine cterm=NONE cterm ...

  9. Selenium 方法封装 一

    Selenium 封装 Selenium 封装 WebDriver对页面的操作,需要找到一个WebElement,然后再对其进行操作,比较繁琐: WebElement element =driver. ...

  10. 磁盘结构,平均寻道时间,平均延迟时间,虚拟内存与MMU

    首先了解一下磁盘:磁盘低速的原因是因为它一种机械装置,在磁盘中有一个或多个金属盘片,它们以5400,7200或10800rpm(RPM =revolutions per minute 每分钟多少转 ) ...