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. pymsql与ORM--python操作MySQL之利器

    pymsql 原生模块 pymsql是python中操作MySQL的模块,其使用方法和MySQLdb几乎相同. 下载安装 pip3 install pymysql 使用操作 1.执行SQL impor ...

  2. 网络编程 - 1.简单的套接字通信/2.加上通信循环/3.bug修复/4.加上链接循环/5.模拟ssh远程执行命令

    1.简单的套接字通信 服务端 ''' 服务端 接电话 客户端 打电话 1.先启动服务端 2.服务端有两种套接字 1.phone 用来干接收链接的 2.conn 用来干收发消息的 ''' import ...

  3. 网络爬虫之scrapy框架设置代理

    前戏 os.environ()简介 os.environ()可以获取到当前进程的环境变量,注意,是当前进程. 如果我们在一个程序中设置了环境变量,另一个程序是无法获取设置的那个变量的. 环境变量是以一 ...

  4. Jersey 出现415 MediaType is not supported问题的原因

    前段时间在使用jersey的时候,经常碰到这个问题,一直没有找到真正的原因.找了其他的解决访问,比如使用jackson以及手动转为json再返回给前端. 后续发现问题出在domain对象属性类型和se ...

  5. Jenkins的安装及邮件配置

    Jenkins介绍  Jenkins,是基于Java开发的一种持续集成工具,用于监控秩序重复的工作,包括: 1).持续的软件版本发布/测试项目. 2).监控外部调用执行的工作. Jenkins安装 j ...

  6. 转Hibernate 一对多关联的CRUD__@ManyToOne(cascade=(CascadeType.ALL))

    一:Group和Users两个类 假定一个组里有n多用户,但是一个用户只对应一个用户组. 1.所以Group对于Users是“一对多”的关联关系@OneToMany Users对于Group是“多对一 ...

  7. 如何用meavn构建mahout项目

    (1)下载meavn  解压到D盘

  8. 微信小程序组件switch

    表单组件switch:官方文档 Demo Code: Page({ switch1Change: function (e){ console.log('switch1 发生 change 事件,携带值 ...

  9. javaScript动画3 事件对象event onmousemove

    事件对象的获取(event的获取) var event = event || window.event;(主要用这种) screenX.pageX和clientX的区别 PageY/pageX: 鼠标 ...

  10. 带你走进AJAX(1)

    ajax是什么? (1)ajax (asynchronouse javascript and xml) 异步的javascript 和xml (2)ajax是一个粘合剂,将javascript.xml ...