`
yaasshole
  • 浏览: 665627 次
文章分类
社区版块
存档分类
最新评论

Singleton之C++部分一

 
阅读更多

<!-- Page published by Emacs Muse begins here -->

采用静态或者全局变量的实现方案

由于C++不能保证静态或者全局对象的构造函数的调用顺序以及析构顺序。所以如果程序中有多个用此方法实现的Singleton类,它们之间又有某种构造依赖关系和析构依赖关系,就会造成灾难性的后果。所以,只有当肯定不会有构造和析构依赖关系的情况下,这种实现才是合适的。

> 优点 实现简单,多线程下安全
> 缺点 如果有多个Singleton对象的创建顺序有依赖时,千万别用;不是lazy loading,有些浪费。

Meyers Singleton来控制构造顺序,但是不能控制析构顺序

Scott Meyer在<<Effective C++>>3rd Item4中提出了一个解决方案,当将non-local static变量移动到静态方法中成为local static变量的时候。C++保证当第一次静态方法被调用的时候,才会创建该静态变量。但是这里有一个疑问,创建顺序能够被控制了,可是析构顺序呢?我们只知道进程结束的时候,local static 变量会被析构,而且按照创建顺序的相反顺序进行。如果几个Singleton类的析构函数之间也有依赖关系,并且这种依赖顺序关系和LIFO顺序冲突,就会造成dead-reference问题。

> 优点 实现简单;用的时候才创建,比较节省。
> 缺点 多线程下不安全;如果有多个Singleton对象的析构顺序有依赖时,要小心

DCLP 98标准下是不可靠的,0x标准下是可靠的

DCLP 就是 Double-checked locking pattern.用于在多线程环境下保证只创建Singleton对象。第一次check不用加锁,但是第二次check和创建对象必须加锁。还要注意编译器可能会优化代码,导致DCLP模式失效。因此要使用volatile 修饰T* pInstance变量。先看一下 DCLP的实现代码:




在c++98标准下,这是不可靠的。原因有三点: 一,执行顺序得不到保证。编译器会优化代码,从而改变执行顺序。 pInstance = new Singleton; 这个语句会分成三步完成:1.分配内存,2.在已经分配的内存上调用构造函数创建对象,3.将对象赋值给指针pInstance.但是这个顺序很可能会被改变为1,3,2。如果A线程在1,3执行完后,B线程执行第一个条件判断if(pInstance ==0),此时锁不能起到保护作用。B线程会认为pInstance已经指向有效对象,可以去使用了。嘿嘿,灾难发生。主要原因是C++98标准中没有包含多线程,只假定是单线程,编译器的优化行为无视多线程环境,因此产生的优化代码可能会被去掉或者改变顺序。我们没有办法在98标准的采用标准c++语言来解决这个问题,只能采用平台相关的多线程API和与之兼容的编译器来解决。因此,从本质上来说,基于98标准,此问题无解。 二,volatile对于执行顺序也没有帮助。 三,多处理器的系统,B处理器看到变量值的顺序可能和A处理器写变量值的顺序不一致。 详细解释请参考Scott Meyers and Andrei Alexandrescu的论文:http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf 技术总是发展的,2011标准的出台给DCLP带来了曙光,真的还能用么,拭目以待吧. 让我们先下个结论:

> 缺点 98标准下不可用
> 优点 让我们接受教育,包括Andrei和Scott meyer都犯过错。

Andrei说4.11 scott meyer阐述了0x标准下,由于有了线程概念,内存模型,sequence point被sequenced before 和 happens before取代, 有了atomic等等,DCLP又可以复活了。 http://cppandbeyond.com/2011/04/11/session-announcement-the-c0x-memory-model-and-why-you-care/ 具体谈了什么呢?我还没有找到相关的文档。

简单锁

于是又回到老土的锁方案,其实注意一下调用,还是能够提高效率的。




客户调用时,在每个线程的开头都获得Singleton* p = Singleton::instance();以后就一直使用这个p变量,应该说还是能有效的降低同步的机会。避免频繁调用Singleton::instance()->就好。

> 优点 实现简单,线程安全
> 缺点 客户需要意识到,并且遵守少调用的原则。

程序开始之前创建Singleton对象

严格来说,这是个策略。将要初始化的放到程序最开始初始化。在这个策略下,以上几种方案都是可以的,包括DCLP。因为总是在单线程中创建对象。

<!-- Page published by Emacs Muse ends here -->
分享到:
评论

相关推荐

    C++轻量级通用插件框架源码

    采用智能指针类来管理接口的引用计数及生命期,可从一个接口动态转换为另一个接口(内部采用C++的RTTI机制动态转换),可以区分插件内部的接口引用和插件外部的接口引用。 d) 模块透明部署 一个模块只需要使用其他...

    设计模式 c++ 代码示例

    这是关于设计模式的c++代码,涵盖了abstractFactory, Builder, Adapter, Components,Singleton,Prototype,Bridge 还有未完的部分 将下次再传。

    Linux多线程服务端编程:使用muduo C++网络库

    第1部分C++ 多线程系统编程 第1章线程安全的对象生命期管理3 1.1当析构函数遇到多线程. . . . . . . . . . . . . . . . .. . . . . . . . . . . 3 1.1.1线程安全的定义. . . . . . . . . . . . . . . . .. . . . . ....

    Visual C++ 编程资源大全(英文源码 网络)

    method.zip Function Pointers to Non-Static Object Methods(24KB)&lt;END&gt;&lt;br&gt;77,singleton.zip Creating Singleton Objects using Visual C++ (59KB)&lt;END&gt;&lt;br&gt;78,01.zip Connecting to a running instance ...

    singleton factory

    在这个程序中,在内部(非界面部分)用了3种设计模式:单体模式,工厂模式,门面模式.和vector容器,希望能对大家有点用

    敏捷软件开发:原则、模式与实践

    第一部分 敏捷开发 第1章 敏捷联盟 第2章 极限编程概述 第3章 计划 第4章 测试 第5章 重构 第6章 一次编程实践 第II部分 敏捷设计 第7章 什么是敏捷设计 第8章 单一职责原则(SRP) 第9章 开放—封闭原则...

    二十三种设计模式【PDF版】

    设计模式之 Singleton(单态/单件) 阎宏博士讲解:单例(Singleton)模式 保证一个类只有一个实例,并提供一个访问它的全局访问点 设计模式之 Factory(工厂方法和抽象工厂) 使用工厂模式就象使用 new 一样频繁. ...

    敏捷软件开发原则、模式与实践 C#版

    曾担任C++ Report杂志主编多年,也是设计模式和敏捷开发运动的主要倡导者之一。 目录 第一部分 敏捷开发 第1章 敏捷实践 第2章 极限编程概述 第3章 计划 第4章 测试 第5章 重构 第6章 一次编程实践 第二部分 敏捷...

    敏捷软件开发:原则、模式与实践.pdf

    这本综合性、实用性的敏捷开发和极限编程方面的指南,是由敏捷开发的创始人之一所撰写的。 ●讲述在预算和时间要求下,软件开发人员和项目经理如何使用敏捷开发完成项目。 ●使用真实案例讲解如何用极限编程来设计...

    敏捷软件开发:原则、模式与实践.pdf 高清

    本书于2003年荣获第13届软件开发图书震撼大奖,适于用作高校计算机专业本科生、研究生和软件学院的软件工程和软件开发相关课程的教材或参考书,也适于软件开发和管理人员提高自身水平学习之用。 目录 第Ⅰ部分 敏捷...

    java 设计模式资料

    Singleton:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 State:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。 Strategy:定义一系列的算法,把它们一个个封装...

    Head.First设计模式_PDF.part1

    第1章到第11章陆续介绍的设计模式为Strategy、Observer、Decorator、Abstract Factory、Factory Method、Singleton、Command、Adapter、Facade、Templat Method、Iterator、Composite、State、Proxy。最后三章比较...

    JAVA面试题最全集

    5.j2me程序的必需的几个部分 6.c/s与b/s的区别 7.构建一个connect pool,然后再调用它, 8.j2ee平台与dotnet平台的区别 9.ejb的life cycle 10.session bean 和 entity bean的区别 11.ejb中的transaction机制 ...

    超级有影响力霸气的Java面试题大全文档

    抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象。 2.继承:  继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确...

    java 面试题 总结

    抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象。 2.继承: 继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性...

    asp.net知识库

    C++ 泛型编程系列讲座之实施 泛型技巧系列:简单类型选择器 C# 泛型简介 我眼中的C#2.0新功能特性 泛型技巧系列:避免基类及接口约束 New Article 不该用Generics实现Abstract Factory的理由 C#2.0-泛型 C#2.0-...

    java基础题 很全面

    4. 编程题: 写一个Singleton出来。 31 5. 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。 31 6. 写一段Jdbc连Oracle的...

    千方百计笔试题大全

    22、我们在web 应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 10 23、String 和StringBuffer 的区别? 10 24、String, StringBuffer StringBuilder 的区别。 10 25、...

Global site tag (gtag.js) - Google Analytics