【C++设计模式】单件类与DCLP(Double Check Lock Pattern)的风险

【单件类】

保证只能有一个实例化对象,并提供全局的访问入口。

【设计注意事项】

1.阻止所有实例化的方法:

private 修饰构造函数,赋值构造函数,赋值拷贝函数。

2.定义单实例化对象的方法:

a.使用static 修饰

b.使用new+delete的方法

3.多线程版本:

使用双检测锁定,即先检测单实例对象是否存在;不存在,使能“锁”,再次判断实例是否存在,不存在就创建该单实例对象。

A.单层锁示例:

  1. Singleton* Singleton::getInstance() {
  2. Lock lock;      // scope-based lock, released automatically when the function returns
  3. if (m_instance == NULL) {
  4. m_instance = new Singleton;
  5. }
  6. return m_instance;
  7. }

B.DCL示例:【单层锁存在高并发时效率低,DCL提出先检测单件指针m_instance是否已创建,减少大部分的锁;上锁后,再次检查m_instance 】

  1. Singleton* Singleton::getInstance() {
  2. if(m_instance==NULL)
  3. {
  4. Lock lock;      // scope- based lock, released automatically when the function returns
  5. if (m_instance == NULL) {
  6. m_instance = new Singleton;
  7. }
  8. }
  9. return m_instance;
  10. }

【DCL的风险】

回顾下(或者学习下)   m_instance = new Singleton; 发生了什么:

1.分配Singleton对象所需的内存

2.为该内存区域执行构造函数

3.m_instance指向该内存。

一切都似乎没有什么问题,但是有时编译器喜欢把2和3替换下(先不管编译器出于什么目的)

执行单例化构造( m_instance = new Singleton; )的顺序中,其他线程访问对象程序未加锁【lock一般不阻止CPU线程调度程序,只对俩个线程里同样上了同个锁的部分函数有阻塞作用】,直接访问会出故障【操作未定义的对象】,又不能所有地方都加锁--效率低。

解决方法:在单例化构造中先构造给临时变量,再把临时变量赋值给单例化对象的指针,注意防止编译器优化,否则前功尽弃【当然,这种方式的弊端目前尚未考虑到】。

  1. Singleton* Singleton::getInstance() {
  2. volatile Singleton* tmp = m_instance;
  3. ...                     // insert memory barrier
  4. if (tmp == NULL) {
  5. Lock lock;
  6. tmp = m_instance;
  7. if (tmp == NULL) {
  8. tmp = new Singleton;
  9. ...             // insert memory barrier
  10. m_instance = tmp;
  11. }
  12. }
  13. return tmp;
  14. }

【背景知识】

2000年,一个JAVA高性能研究小组发布了一篇声明《双重检查锁定可能导致锁定无效》。

2004年,Scott Meyers 和Andrei Alexandrescu联合发表了一篇名为《C++实现双重检查锁定存在严重缺陷

【参考链接】

http://blog.csdn.net/nodeathphoenix/article/details/51657973

http://developer.51cto.com/art/201311/419604.htm

时间: 2024-10-12 21:04:22

【C++设计模式】单件类与DCLP(Double Check Lock Pattern)的风险的相关文章

C++设计模式-单件

理解 1.       Singleton模式用来取代全局静态变量.C++通过静态成员变量来实现类实例全局唯一性. 2.       instance()方法是单件提供的唯一调用入口. 要点 1.       为了防止外界调用产生多个实例,将构造方法.析构方法.拷贝构造方法.赋值重载方法都作为protected. 2.       instance()方法产生对象方式有两种:使用局部static对象,生命期在首次进入局部生命期产生(见下面),在程序结束时销毁:通过new产生新对象,在析构方法中d

设计模式 - 单件模式(singleton pattern) 详解

单件模式(singleton pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/28595349 单件模式(singleton pattern) : 确保一个类只有一个实例, 并提供一个全局访问点. 单价模式包括3个部分: 私有构造器, 静态变量, 静态方法. 具体方法: 1. 标准的单例模式: /** * @time 2014.6.5 */ package singleton; /** * @author

说说设计模式~单件模式(Singleton)

单件模式(Singleton)要求一个类有且仅有一个实例,并且提供了一个全局的访问点. 从概念上来研究一下它的实现,不考虑线程安全 1 public sealed class Singlton 2 { 3 static Singlton instance = null; 4 private Singlton() { } 6 7 public static Singlton Instance 8 { 9 get 10 { 11 if (instance == null) 12 { 13 insta

Double Check形式的单例模式

这两天在看开源项目时,发现Event Bus和Universalimageloader中写单例模式都是Double Check的形式.平时总是看到各种各样的单例模式,如,饿汉式,懒汉式等等.其中大多存在问题.今天记录一种比较优秀的单例模式的写法------Double Check.以后我准备就用这种方法了.(虽然还有其他优秀的方式,比如内部静态类,枚举) 先上代码: public class ImageLoader { private volatile static ImageLoader in

设计模式大类--行为模式(上)

大概有10中行为模式,分为上中下三篇.一.Template(模板)描述:定义一些操作算法的骨架,将其实现延迟到其子类好处:扩展性强 例子:Java的抽象类本来就是Template模式,因此使用很普遍.而且很容易理解和使用,我们直接以示例开始: public abstract class Benchmark{ /** * 下面操作是我们希望在子类中完成 */ public abstract void benchmark(); /** * 重复执行benchmark次数 */ public fina

【小话设计模式】类之间的关系

4.组合(Composition) 定义:相比于聚合,组合是一种耦合度更强的关联关系.存在组合关系的类表示"整体-部分"的关联关系,"整体"负责"部分"的生命周期,他们之间是共生共死的:并且"部分"单独存在时没有任何意义.如果是组合关系,如果整体被破坏则个体一定会被破坏,而聚合的个体则可能是被多个整体所共享的,不一定会随着某个整体的破坏而被破坏. 符号:带实心菱形实线箭头表示 1.合成关系是关联关系的一种,是比聚合关系还要强的

设计模式大类--结构模式(上)

大概有7中结构模式,分为上下两篇.一.Adapter(适配器)描述:将两个不兼容的类结合一起使用,一般需要用到其中某个类的若干方法好处:在两个类直接创建一个混合接口,而不必修改类里面的其他代码 例子:假设我们要打桩,有两种类:方形桩 圆形桩.public class SquarePeg{ public void insert(String str){ System.out.println("SquarePeg insert():"+str); } } public class Roun

java异常处理:建立exception包,建立Bank类,类中有变量double balance表示存款,Bank类的构造方法能增加存款,Bank类中有取款的发方法withDrawal(double dAmount),当取款的数额大于存款时,抛出InsufficientFundsException,取款数额为负数,抛出NagativeFundsException,如new Bank(100),

建立exception包,建立Bank类,类中有变量double  balance表示存款,Bank类的构造方法能增加存款,Bank类中有取款的发方法withDrawal(double dAmount),当取款的数额大于存款时,抛出InsufficientFundsException,取款数额为负数,抛出NagativeFundsException,如new Bank(100),表示存入银行100元,当用方法withdrawal(150),withdrawal(-15)时会抛出自定义异常. pa

设计模式基础:类及类关系的UML表示

设计模式基础:类及类关系的UML表示 2009-10-26 17:00 by 宗哥, 1891 阅读, 1 评论, 收藏, 编辑 UML中,类关系分为这几种,泛化(generalization), 实现(realization),依赖(Dependency),关联(associate),聚合(aggregation),(composition)下面分别是UML实现及C#中的代码表现. 泛化(generalization) 泛化也称作特化(specialization),用来表示一个更一般和更特殊