c++之单例模式
1 本篇主要讨论下多线程下的单例模式实现:
首先是 double check 实现方式: 这种模式可以满足多线程环境下,只产生一个实例。
- template<typename T>
- class dclsingleton
- {
- public:
- static T& GetInstance()
- {
- if(NULL == value_)
- {
- MutexGuard mg(mutex_);
- if (NULL == value_)
- {
- value_ = new T;
- }
- }
- return *value_;
- }
- protected:
- dclsingleton() { std::cout << "dclsingleton constuctor called" << std::endl; }
- dclsingleton(const dclsingleton &dcl) {}
- private:
- static T* value_;
- static Mutex mutex_;
- };
但是这种实现存在除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(); 后 实现是这样的:
- static T& GetInstance()
- {
- if(NULL == value_)
- {
- MutexGuard mg(mutex_);
- if (NULL == value_)
- {
- T* tmp = static_cast<T*>(operator new (sizeof(T)));
- new (tmp) T();
- __sync_synchronize();
- value_ = tmp;
- }
- }
- return *value_;
- }
这样便可以既保证多线程环境安全,又保证不会出现上面的问题。
2. 加上内存屏障的示例代码:dcl_single.h
- #ifndef __DCL_SINGLE_H
- #define __DCL_SINGLE_H
- #include <iostream>
- namespace yl
- {
- class Mutex
- {
- public:
- Mutex()
- {
- pthread_mutex_init(&mutex_, NULL);
- }
- ~Mutex()
- {
- pthread_mutex_destroy(&mutex_);
- }
- public:
- void Lock()
- {
- pthread_mutex_lock(&mutex_);
- }
- void UnLock()
- {
- pthread_mutex_unlock(&mutex_);
- }
- private:
- pthread_mutex_t mutex_;
- };
- class MutexGuard
- {
- public:
- MutexGuard(Mutex& m) : mutex_(m)
- {
- mutex_.Lock();
- }
- ~MutexGuard()
- {
- mutex_.UnLock();
- }
- private:
- Mutex mutex_;
- };
- template<typename T>
- class dclsingleton
- {
- public:
- static T& GetInstance()
- {
- if(NULL == value_)
- {
- MutexGuard mg(mutex_);
- if (NULL == value_)
- {
- T* tmp = static_cast<T*>(operator new (sizeof(T)));
- new (tmp) T();
- __sync_synchronize();
- value_ = tmp;
- }
- }
- return *value_;
- }
- protected:
- dclsingleton() { std::cout << "dclsingleton constuctor called" << std::endl; }
- dclsingleton(const dclsingleton &dcl) {}
- private:
- static T* value_;
- static Mutex mutex_;
- };
- template<typename T>
- T* dclsingleton<T>::value_ = NULL;
- template<typename T>
- Mutex dclsingleton<T>::mutex_;
- }
- #endif
singletonTest.cpp
- #include "dcl_single.h"
- #include <iostream>
- namespace yl
- {
- class MgrSg : public dclsingleton<MgrSg>
- {
- private:
- friend class dclsingleton <MgrSg>;
- MgrSg(){ std::cout << "MgrSg: constructor called" << std::endl; }
- ~MgrSg() { std::cout << "MgrSg: desconstructor called" << std::endl; }
- public:
- void print()
- {
- std::cout << "print called" << std::endl;
- }
- };
- }
- int
- main(void)
- {
- using namespace yl;
- MgrSg::GetInstance().print();
- return ;
- }
3. 还可以用 unix 下的 pthread_once 来实现单例模式:
- template <typename T>
- class MySingleton
- {
- public:
- static T & getInstance()
- {
- pthread_once(&ponce_, &MySingleton::init);
- return *instance;
- }
- protected:
- MySingleton() {}
- MySingleton(const MySingleton&) {}
- private:
- static void init()
- {
- instance = new T();
- }
- private:
- static pthread_once_t ponce_;
- static T *instance;
- };
- template<typename T>
- pthread_once_t MySingleton<T>::ponce_ = PTHREAD_ONCE_INIT;
- template<typename T>
- T *MySingleton<T>::instance = nullptr;
- }
4.我自己遇到的就是以上两种情况,若是希望了解更全面,可参考下边:
http://www.cnblogs.com/liyuan989/p/4264889.html
5. 水平有限,望及时指出错误。谢谢
c++之单例模式的更多相关文章
- C++实现线程安全的单例模式
在某些应用环境下面,一个类只允许有一个实例,这就是著名的单例模式.单例模式分为懒汉模式,跟饿汉模式两种. 首先给出饿汉模式的实现 template <class T> class sing ...
- 23种设计模式--单例模式-Singleton
一.单例模式的介绍 单例模式简单说就是掌握系统的至高点,在程序中只实例化一次,这样就是单例模式,在系统比如说你是该系统的登录的第多少人,还有数据库的连接池等地方会使用,单例模式是最简单,最常用的模式之 ...
- angular2系列教程(十)两种启动方法、两个路由服务、引用类型和单例模式的妙用
今天我们要讲的是ng2的路由系统. 例子
- java设计模式之--单例模式
前言:最近看完<java多线程编程核心技术>一书后,对第六章的单例模式和多线程这章颇有兴趣,我知道我看完书还是记不住多少的,写篇博客记录自己所学的只是还是很有必要的,学习贵在坚持. 单例模 ...
- 设计模式C#合集--单例模式
单例模式 代码: 第一种: private static Singleton singleton = null; private Singleton() { } public static Singl ...
- 设计模式之单例模式(Singleton)
设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...
- GOF23设计模式之单例模式
·核心作用: -保证一个类只有一个实例,并且提供一个访问该实例的全局访问点. ·常见应用场景: -Windows的Task Manager(任务管理器)就是很典型的单例模式 -Windows的Recy ...
- GJM : C#设计模式(1)——单例模式
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- PHP设计模式(四)单例模式(Singleton For PHP)
今天讲单例设计模式,这种设计模式和工厂模式一样,用的非常非常多,同时单例模式比较容易的一种设计模式. 一.什么是单例设计模式 单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对 ...
- java设计模式之单例模式(几种写法及比较)
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
随机推荐
- pymsql与ORM--python操作MySQL之利器
pymsql 原生模块 pymsql是python中操作MySQL的模块,其使用方法和MySQLdb几乎相同. 下载安装 pip3 install pymysql 使用操作 1.执行SQL impor ...
- 网络编程 - 1.简单的套接字通信/2.加上通信循环/3.bug修复/4.加上链接循环/5.模拟ssh远程执行命令
1.简单的套接字通信 服务端 ''' 服务端 接电话 客户端 打电话 1.先启动服务端 2.服务端有两种套接字 1.phone 用来干接收链接的 2.conn 用来干收发消息的 ''' import ...
- 网络爬虫之scrapy框架设置代理
前戏 os.environ()简介 os.environ()可以获取到当前进程的环境变量,注意,是当前进程. 如果我们在一个程序中设置了环境变量,另一个程序是无法获取设置的那个变量的. 环境变量是以一 ...
- Jersey 出现415 MediaType is not supported问题的原因
前段时间在使用jersey的时候,经常碰到这个问题,一直没有找到真正的原因.找了其他的解决访问,比如使用jackson以及手动转为json再返回给前端. 后续发现问题出在domain对象属性类型和se ...
- Jenkins的安装及邮件配置
Jenkins介绍 Jenkins,是基于Java开发的一种持续集成工具,用于监控秩序重复的工作,包括: 1).持续的软件版本发布/测试项目. 2).监控外部调用执行的工作. Jenkins安装 j ...
- 转Hibernate 一对多关联的CRUD__@ManyToOne(cascade=(CascadeType.ALL))
一:Group和Users两个类 假定一个组里有n多用户,但是一个用户只对应一个用户组. 1.所以Group对于Users是“一对多”的关联关系@OneToMany Users对于Group是“多对一 ...
- 如何用meavn构建mahout项目
(1)下载meavn 解压到D盘
- 微信小程序组件switch
表单组件switch:官方文档 Demo Code: Page({ switch1Change: function (e){ console.log('switch1 发生 change 事件,携带值 ...
- javaScript动画3 事件对象event onmousemove
事件对象的获取(event的获取) var event = event || window.event;(主要用这种) screenX.pageX和clientX的区别 PageY/pageX: 鼠标 ...
- 带你走进AJAX(1)
ajax是什么? (1)ajax (asynchronouse javascript and xml) 异步的javascript 和xml (2)ajax是一个粘合剂,将javascript.xml ...