• C++单例的安全实现,double-check(双重检查锁定)的安全实现方法


    概述

    • 单例模式指在整个系统生命周期里,保证一个类只能产生一个实例,确保该类的唯一性。

    • 单例类特点

      • 构造函数和析构函数为private类型,目的禁止外部构造和析构
      • 拷贝构造和赋值构造函数为private类型,目的是禁止外部拷贝和赋值,确保实例的唯一性
      • 类里有个获取实例的静态函数,可以全局访问
    • 单例模式可以分为懒汉式和饿汉式,两者之间的区别在于创建实例的时间不同:

      • 懒汉式:指系统运行中,实例并不存在,只有当需要使用该实例时,才会去创建并使用实例。(这种方式要考虑线程安全)
      • 饿汉式:指系统一运行,就初始化创建实例,当需要时,直接调用即可。(本身就线程安全,没有多线程的问题)

    C++11 饿汉式实现

    Singleton& Singleton::getInstance() {
        static Singleton instance;
        return instance;
    }
    
    • 1
    • 2
    • 3
    • 4

    一般推荐使用这种简单的方式,安全好用!

    C++11 懒汉式实现

    要实现安全的懒汉式不容易

    • 传统的double-check实现方法如下:
    Singleton* Singleton::getInstance() {
    	if (m_instance)
    		return m_instance;
        Lock lock;      // scope-based lock, released automatically when the function returns
        if (m_instance == NULL) {
            m_instance = new Singleton;
        }
        return m_instance;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    严格意义上说,上面的实现方法是不是完全安全的,因为第一次读取m_instance不受锁或类似东西的保护;

    • 而基于C++11提供的atomic就可以实现一种更安全的懒汉式单例,代码如下:
    std::atomic<Singleton*> Singleton::m_instance;
    std::mutex Singleton::m_mutex;
    
    Singleton* Singleton::getInstance() {
        Singleton* tmp = m_instance.load();
        if (tmp == nullptr) {
            std::lock_guard<std::mutex> lock(m_mutex);
            tmp = m_instance.load();
            if (tmp == nullptr) {
                tmp = new Singleton;
                m_instance.store(tmp);
            }
        }
        return tmp;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 完整测试代码如下:
    
    #include 
    #include 
    #include 
    #include 
    #include 
    
    class Singleton {
    
    public:
    
        static Singleton* getInstance() {
            Singleton* tmp = m_instance.load();
            if (tmp == nullptr) {
                std::lock_guard<std::mutex> lock(m_mutex);
                tmp = m_instance.load();
                if (tmp == nullptr) {
                    tmp = new Singleton;
                    m_instance.store(tmp);
                }
            }
            return tmp;
        }
    
        ~Singleton() {
            std::cout << "~Singleton() called!" << std::endl;
        }
    
        void print() {
    
            if (m_instance == nullptr) 
                std::cout << "m_instance is null" << std::endl;
            else
                std::cout << "m_instance is not null" << std::endl;
        }
    
    private:
        Singleton() = default;
        Singleton(const Singleton& Singleton) = default;
        static std::atomic<Singleton*> m_instance;
        static std::mutex m_mutex;
    };
    
    std::atomic<Singleton*> Singleton::m_instance;
    std::mutex Singleton::m_mutex;
    
    int main()
    {
        Singleton::getInstance()->print();
        std::thread([]{ Singleton::getInstance()->print(); }).detach();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    输出:

    m_instance is not null
    m_instance is not null
    
    • 1
    • 2

    参考

    is-implementation-of-double-checked-singleton-thread-safe
    double-checked-locking-is-fixed-in-cpp11
    C++11 中的双重检查锁定模式
    陈硕智能指针线程安全_linux C++ 线程安全的单例模式总结

  • 相关阅读:
    单元测试Junit使用与详解
    回Mixlab三天,“创造力团队”治好了我的精神内耗
    Java代码审计面试
    搭建DNS服务器和selinux
    【力扣周赛】第 361 场周赛(⭐前缀和+哈希表 & 树上倍增、LCA⭐)
    【开源】JAVA+Vue.js实现个人健康管理系统
    晶振是如何起振的
    听说JetBrains要涨价,我赶紧把Goland续费到2025年!!!
    电脑视频怎么转音频mp3
    信息学奥赛一本通:2038:【例5.5】最大数位置
  • 原文地址:https://blog.csdn.net/stallion5632/article/details/126218126