zoukankan      html  css  js  c++  java
  • C++线程安全的单例模式

     
    // C++11跨平台实现线程安全的DCL(Double Check Lock)单例,类似Java的volatile实现内存屏障,阻止CPU指令重排序
    class Single {
        Single(){}
        Single(const Single& other) = delete;
        Single& operator=(const Single& other) = delete;
        static std::atomic<Single*> m_instance;
        static std::mutex m_mutex;
    public:
        static Single* GetInstance() {
            Single* tmp = m_instance.load(std::memory_order_relaxed);
            std::atomic_thread_fence(std::memory_order_acquire);            // 获取内存fence
            if (tmp == nullptr) {
                std::lock_guard<std::mutex> locker(m_mutex); // 加锁, RAII
                tmp = m_instance.load(std::memory_order_relaxed);
                if (tmp == nullptr) {
                    tmp = new Single;
                    std::atomic_thread_fence(std::memory_order_release);    // 释放内存fence
                    m_instance.store(tmp, std::memory_order_relaxed);
                }
            }// 结束后,锁自动释放
    
            return tmp;
        }
    };
    std::mutex Single::m_mutex;
    std::atomic<Single*> Single::m_instance;
    // 局部static变量实现泛型单例管理类,C++能够保证static变量只会被创建一次
    template<typename T>
    class Singleton {
       Singleton() = delete;
       Singleton(const Singleton& other) = delete;
       Singleton& operator=(const Singleton& other) = delete;
    public:
       inline static T& GetInstance() {
           static T instance;// T必须能够执行默认初始化或提供了默认构造函数
           return instance;
       }
    };
    // 外部使用方法,只需要对外暴露Singleton<ClassName>就能实现对ClassName的单例管理
    // 简单饿汉式,也可以使用局部static变量,这样就能等到调用GetInstance()函数时才会真正创建单例对象
    class Singleton {
       Singleton() {}
       Singleton(const Singleton& other) = delete;
       Singleton& operator=(const Singleton& other) = delete;
       static Singleton m_instance;
    public:
       inline static Singleton* GetInstance() {
            return &m_instance;
       }
    };
    // 真正定义,分配内存的地方
    Singleton Singleton::m_instance;

     C++中volatile关键字和Java的volatile关键字实现的功能不一样:

       C++中volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。

      当两个线程都要用到某一个变量且该变量的值会被改变时,应该用volatile声明,该关键字的作用是防止优化编译器把变量从内存装入CPU寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值。

      Java中volatile关键字有2个作用:1、保证线程之间变量内存的可见性;2、阻止CPU指令重排序

  • 相关阅读:
    暴力程序之回文子串
    关于取消同步带来问题的样例
    JavaScript之Date
    JavaScript之array
    智破连环阵
    超长数字串
    无向图最短路径
    扫雷
    n!最末尾非0数
    计算程序运行时间
  • 原文地址:https://www.cnblogs.com/djh5520/p/14748251.html
Copyright © 2011-2022 走看看