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

    /*
        代码中经常会使用到单例模式,单例模式就是隐藏构造函数,提供获取一个实例的静态方法。
        但是在多线程场景下,单例模式会有一些不同。例如Config类的instance方法如下
        */
        //获取一个实例(对外接口)
        static Config * instance()
        {
            if (NULL == m_instance)
            {
                //加锁(多线程场景下)
                m_mutex.acquire();
                if (NULL == m_instance)
                {
                    m_instance = new Config();
                    /*
                    类似于这个类的初始化,我是不建议放在这里的,
                    因为如果init方法执行失败,但是实例仍然不为NULL,
                    建议在main函数中第一次调用instance方法时,执行init方法初始化实例
                    (注意init方法也是只能执行一次的,请考虑多线程场景)
    
                    init方法放在这个纯粹是为了解释这个场景下单例的使用
                    */
                    m_instance->init();
                }
                //解锁
                m_mutex.release();
            }
            return m_instance;
        }
    /*
    如果在instance方法中不加锁,在多线程的场景下,有可能创建出多个实例。
    instance方法在加锁之后,还是有问题的。
    假设线程A正在执行m_instance->init()方法(init方法执行的时间很长),此时线程B开始执行instance方法,
    发现m_instance != NULL(因为线程A已经构造了该实例),那么线程B就会直接获取到这个并没有执行完init方法的m_instance实例,
    线程B用这个m_instance去执行操作,就会出现问题。
    */
    /*
    简单的改进就是,去掉前边的判断,直接加锁,这样就避免了该问题,
    线程B进行进来的时候因为线程A已经获取到锁,线程B会等待,
    等到线程A释放锁之后(所有初始化操作已经完成),线程B判断m_instance != NULL,
    线程B可以使用m_instance这个实例了
    */
    static Config * Config::instance()
    {
        //加锁(多线程场景下)
        m_mutex.acquire();
        if (NULL == m_instance)
        {
            m_instance = new Config();
            m_instance->init();
        }
        //解锁
        m_mutex.release();
    return m_instance; }
    /*
    但是这样的改进会出现一个新问题,就是每次调用这个单例就会加锁判断,频繁调用会影响速度
    */
    /*
        再次改进方案,使用一个临时变量构造,初始化,成功后再赋值给m_instance
        这样避免了多线程操作影响,又不影响速度
        */
        static Config * instance()
        {
            if (NULL == m_instance)
            {
                //加锁(多线程场景下)
                m_mutex.acquire();
                if (NULL == m_instance)
                {
                    Config * pInstance = new Config();
                    pInstance->init();
                    m_instance = pInstance;
                }
                //解锁
                m_mutex.release();
            }
            return m_instance;
        }
  • 相关阅读:
    数据库简介
    计算机网络OSI七层协议
    信息论知识点(绪论)
    Wireshark抓取HTTP数据包
    配置FileZilla FTP服务器
    Redis集群搭建的几种方式
    Redis单个分片高可用&哨兵集群
    Redis哈希一致性&对应API操作
    MapReduce实现好友推荐
    window下使用IDEA远程调试伪分布式hadoop集群
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/7534989.html
Copyright © 2011-2022 走看看