再谈单例模式
来源:互联网 发布:html5 淘汰桌面软件 编辑:程序博客网 时间:2024/05/29 12:26
之前写过一篇博客 《C++单例模式的模板基类》 http://blog.csdn.net/kentzhang_/article/details/48206821
但是,最近才发现实际 上 static T* Instance() 的实现是有一点bug 的,下面分析。
static T *Instance() { if(NULL != m_Instance) { return m_Instance; } m_Mutex.Lock(); if(NULL != m_Instance) { m_Mutex.UnLock(); return m_Instance; } m_Instance = new(std::nothrow) T(); m_Mutex.UnLock(); return m_Instance; }
这种实现在多线程环境下,可能会有bug ,原因就在 m_Instance = new (std::nothrow) T() 这行代码。
这句代码实际上分三步执行:
1、分配内存
2、调用构造函数,初始化内存空间
3、将内存地址赋值给单例指针
代码可转化为如下形式:
T* p = newMemory(sizeof(T))
p->BaseSingleton::BaseSingleton()
m_Instance = p
编译器出于优化的目的,可能会将第一步和第三步合并,变成如下:
m_Instance = newMemory(sizeof(T))
m_Instance->BaseSingleton::BaseSingleton()
那么在执完第一行代码时,有可能会切换到其他线程,其他线程如果调用 Instance()函数,由于m_Insatnce已经赋值,将返回这个指针,但是
指针指向的内存并未初始化,所以会造成不可预知的错误。
在Boost库中,有一种很好的单例实现模式,我做了一点修改,就是引用改成指针。代码如下:
#ifndef BASESINGLETON_H#define BASESINGLETON_H/** 单例模式采用boost源码 由于boost单例返回的是引用,下面改成指针 */template<class T>class BaseSingleton{public: BaseSingleton(){}private: struct object_creator { // This constructor does nothing more than ensure that instance() // is called before main() begins, thus creating the static // T object before multithreading race issues can come up. object_creator() { BaseSingleton<T>::Instance(); } inline void do_nothing() const { } }; static object_creator create_object; //BaseSingleton();public: typedef T object_type; // If, at any point (in user code), BaseSingleton<T>::instance() // is called, then the following function is instantiated. static object_type* Instance() { // This is the object that we return a reference to. // It is guaranteed to be created before main() begins because of // the next line. static object_type obj; // The following line does nothing else than force the instantiation // of BaseSingleton<T>::create_object, whose constructor is // called before main() begins. create_object.do_nothing(); return &obj; }};template <class T>typename BaseSingleton<T>::object_creatorBaseSingleton<T>::create_object;#endif // BASESINGLETON_H
我之前实现的单例模式中,必须是第一次手动调用Instance()才生成单例对象,这样就引入了多线程的问题。
而Boost实现方式,在单例类中定义一个内嵌的静态的结构体,这个结构体生成时调用自己的构造函数,构造函数中执行Instance()函数,由于单例类内的静态的结构体生成时,是在main()执行之前,所以巧妙地绕开了多线程的问题。
0 0
- 再谈单例模式
- 再谈单例模式
- 模式
- 模式
- 模式
- 模式
- 模式
- 模式
- 模式
- 模式
- 模式
- 模式
- 模式
- 模式
- 模式
- 模式
- 模式
- 模式
- java程序员第十一课 javaweb之request&response
- apache虚拟主机设置
- Javascript编程风格
- SSH端口转发(隧道)
- ios 剪裁图片
- 再谈单例模式
- (四)洞悉linux下的Netfilter&iptables:包过滤子系统iptable_filter
- 基于对话框MFC按Enter键或者Ese退出的解决方法
- android 显示隐藏密码
- Python多进程不要使用TimedRotatingFileHandler
- UML图之序列图和协作图
- 并查集 + 拓扑排序 hdu1811 Rank of Tetris
- java面向对象(二)
- android打包传递