zoukankan      html  css  js  c++  java
  • 分享一个线程安全的单例模板类

    单例模式应该说是最简单的设计模式了。在此分享一个线程安全的单例模板类。

    template <typename Type>
    
    class CSingleton
    
    {
    
    public:
    
    static Type* GetInstance()
    
    {
    
    // kBeingCreatedMarker用来表示单例实例正在创建过程中。
    
    // 此处初始化为1是因为操作系统不会分配地址为1的指针。
    
    static const volatile intptr_t kBeingCreatedMarker = 1;
    
    // 如果m_pInstance不为空且不是正在创建,则返回m_pInstance
    
    if (m_pInstance != NULL && m_pInstance != kBeingCreatedMarker)  {
    
    return reinterpret_cast<Type*>(m_pInstance);
    
    }
    
    // 使用InterlockedCompareExchange函数保证原子操作
    
    // 函数判断m_pInstance是否等于NULL,如果是则将m_pInstance赋值为kBeingCreatedMarker
    
    // 函数返回值为m_pInstance的初始值,通过判断返回值是否等于NULL得知是否可以进行实例化
    
    if (InterlockedCompareExchange(
    
    reinterpret_cast<volatile LONG*>(&m_pInstance),
    
    static_cast<LONG>(kBeingCreatedMarker),
    
    static_cast<LONG>(NULL)) == NULL)  {
    
    static Type newval;
    
    m_pInstance = reinterpret_cast<intptr_t>(&newval);
    
    return &newval;
    
    }
    
    // 如果m_pInstance是kBeingCreatedMarker,即表示正在创建中
    
    // SwitchToThread让出剩余的时间片等待创建过程完成
    
    while (m_pInstance == kBeingCreatedMarker)
    
    {
    
    SwitchToThread();
    
    }
    
    // 到达此处表明创建过程已经完成了
    
    return reinterpret_cast<Type*>(m_pInstance);
    
    }
    
    Type& operator*()
    
    {
    
    return *GetInstance();
    
    }
    
    Type* operator->()
    
    {
    
    return GetInstance();
    
    }
    
    private:
    
    static volatile intptr_t m_pInstance;
    
    };
    
    template <typename Type>
    
    volatile intptr_t CSingleton<Type>::m_pInstance = NULL;

    假设我们有个CCmdManager类

    class CCmdManager
    
    {
    
    public:
    
    CCmdManager()
    
    {
    
    std::cout << "Hello, I am the only one!";
    
    };
    
    };

    使用方法很简单,如下:

    int main()
    
    {
    
    CCmdManager *pMgr = CSingleton<CCmdManager>::GetInstance();
    
    CCmdManager &mgr = *(CSingleton<CCmdManager>::GetInstance());
    
    }

    如果我们想要完全限制CCmdManager不被实例化第二次,我们可以这么做

    class CCmdManager
    
    {
    
    private:
    
    CCmdManager()
    
    {
    
    std::cout << "Hello, I am the only one!";
    
    };
    
    friend class CSingleton<CCmdManager>;
    
    };

    通过将构造函数设置为private,且仅对class CSingleton<CCmdManager>开放,就可以保证用户只能使用CCmdManager *pMgr = CSingleton<CCmdManager>::GetInstance()这种方式调用了。

    顺便说一下,这个代码的一些局限性

    1. 因为使用了InterlockedCompareExchange这个函数,所以只能在Windows下使用,但是不可否定的是这个函数的效率极高,完成比较并交换只要一条指令。

    wps2B92.tmp

    2. CSingleton在实例化对象时,只支持默认构造函数。一般情况下,这个也是可以接受的。

  • 相关阅读:
    Spring加载机制
    SpringMVC 请求过程
    Spring事务传播机制
    数组扩容
    hashmap 底层原和扩容机制
    spring源码
    金字塔表达方式(三)如何使得一个事情变得清晰有逻辑
    金字塔表达方式(二)如何判断事情的逻辑是否正确
    C#设计模式(3)——单例模式(Singleton)
    C#设计模式(2)——工厂模式
  • 原文地址:https://www.cnblogs.com/SudoSky/p/4525648.html
Copyright © 2011-2022 走看看