安得情怀似旧时

和气春风贤者坐,静山流水玉人怀

再谈单例模式

之前写过一篇博客 《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()执行之前,所以巧妙地绕开了多线程的问题。






阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/KentZhang_/article/details/49890089
文章标签: C++ 多线程 单例
个人分类: C/C++
上一篇C++单例模式的模板基类
下一篇Linux下POSIX正则表达式API使用
想对作者说点什么? 我来说一句

单例模式单例模式单例模式

2011年07月31日 467KB 下载

研磨单例模式研磨单例模式

2010年12月15日 123KB 下载

单例模式(讲解单例模式)

2011年01月18日 317KB 下载

设计模式再谈

2008年04月05日 249B 下载

单例模式详解~~单例模式详解~~

2011年03月01日 39KB 下载

再谈“把实证研究进行到底

2014年02月03日 972KB 下载

没有更多推荐了,返回首页

关闭
关闭