再谈单例模式

原创 2015年11月17日 17:04:35

之前写过一篇博客 《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_creator
BaseSingleton<T>::create_object;

#endif // BASESINGLETON_H

我之前实现的单例模式中,必须是第一次手动调用Instance()才生成单例对象,这样就引入了多线程的问题。

而Boost实现方式,在单例类中定义一个内嵌的静态的结构体,这个结构体生成时调用自己的构造函数,构造函数中执行Instance()函数,由于单例类内的静态的结构体生成时,是在main()执行之前,所以巧妙地绕开了多线程的问题。






版权声明:本文为博主原创文章,未经博主允许不得转载。

浅谈java单例模式——优点以及为什么使用到synchronized

单例模式的两种形式,解决了,为什么单例模式中要使用同步锁,为什么要进行两次if判断是否为空...
  • IWantToHitRen
  • IWantToHitRen
  • 2015年09月09日 19:23
  • 1468

设计模式——单例模式、工厂模式、代理模式、观察者模式、装饰器模式

设计模式是一种解决方案,用于解决在软件设计中普遍存在的问题,是前辈们对之前软件设计中反复出现的问题的一个总结。 至于我们为什么要学习设计模式,我觉得轮子哥总结的很好 我们学设计模式,是为了学习如...
  • learrrrrrrrn
  • learrrrrrrrn
  • 2017年03月26日 16:55
  • 1263

okhttp的简单介绍(二)之简单封装

前一篇文章简单的介绍了okhttp的简单使用,okhttp的简单介绍(一): 今天来okhttp的第二篇,简单封装,减少代码冗余,代码结构清晰。...
  • wuyinlei
  • wuyinlei
  • 2016年01月28日 10:13
  • 6875

黑马程序员——多线程4:再谈单例设计模式

------- android培训、java培训、期待与您交流! ----------    我们在前面的博客《设计模式1:单例设计模式》(简称《设计模式1》,下同)一文中简单介绍过单例设计模式...
  • axr1985lazy
  • axr1985lazy
  • 2014年11月22日 22:23
  • 281

设计模式再谈

  • 2008年04月05日 18:55
  • 249B
  • 下载

《再谈Python的GIL》测试用例

  • 2014年04月12日 21:37
  • 1KB
  • 下载

再谈适配器模式(很多网上转载的图有问题,大家请注意)

今天实在无语了,看适配器模式并编写程序时,总觉得图上的图画的有问题,但是网上搜索很多有关类的适配器模式博客发现很多博客也是这么画的,百思不得其解,但是坚信有问题,终于在网上找到一个正确的,哎,国人的相...
  • liuyongvs2009
  • liuyongvs2009
  • 2014年12月04日 23:49
  • 379

再谈bridge模式理解小例子

今天回头看了原来写的bridge模式的文章,感觉还是太泛化、理论,不能够方便快速的理解,下面就借这《大话设计模式》中有关bridge模式的解释来谈谈实际实际应用解决的问题。 手机品牌和软件是两个...
  • SunboyJohn690905084
  • SunboyJohn690905084
  • 2016年07月04日 14:04
  • 188

模式识别(Pattern Recognition)学习笔记(二十一)--再谈(人工)神经网络(ANN)

转载出处:http://blog.csdn.net/eternity1118_。 1.简介        目前为止,通过MLP和BP算法的学习,我们已经接触了神经网络,并且知道了最...
  • yangleo1987
  • yangleo1987
  • 2016年11月22日 18:15
  • 1195

再谈STM32的CAN过滤器-bxCAN的过滤器的4种工作模式以及使用方法总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 目录(?)[-] 前言准备工作 1   为什么要过滤器2   两种过滤模式列表模式与掩码模式3   验证码与屏蔽码4...
  • eydwyz
  • eydwyz
  • 2017年03月22日 15:48
  • 248
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:再谈单例模式
举报原因:
原因补充:

(最多只允许输入30个字)