关闭

再谈单例模式

标签: C++多线程单例
181人阅读 评论(0) 收藏 举报
分类:

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






0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:8937次
    • 积分:261
    • 等级:
    • 排名:千里之外
    • 原创:18篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    文章分类