码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 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++ 线程安全的单例模式总结

  • 相关阅读:
    30天黑客(网络安全)自学
    MFC Windows 程序设计[140]之多样消息对话框属性页(附源码)
    景联文科技牵头制定的《信息技术 可扩展的生物特征识别数据交换格式 第4部分:指纹图像数据》国家标准启动会暨研讨会在杭州顺利召开
    Eclipse - Text Editors (文本编辑器)
    java基于springboot家庭水电燃气网上交费系统
    16/32/64位操作系统下,各种变量类型分别占多少字节
    【软件测试】测试人,被裁后已失业大半年该如何破局?
    一文带你熟悉简单实用的Python科学计算库NumPy
    异步链路无法追踪问题解决方案
    Java进阶篇--Condition与等待通知机制
  • 原文地址:https://blog.csdn.net/stallion5632/article/details/126218126
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号