• 【C++设计模式】单件类与DCLP(Double Check Lock Pattern)的风险


    【单件类】
      保证只能有一个实例化对象,并提供全局的访问入口。
    【设计注意事项】
      1.阻止所有实例化的方法:
        private 修饰构造函数,赋值构造函数,赋值拷贝函数。
      2.定义单实例化对象的方法:
        a.使用static 修饰
        b.使用new+delete的方法
      3.多线程版本:
        使用双检测锁定,即先检测单实例对象是否存在;不存在,使能“锁”,再次判断实例是否存在,不存在就创建该单实例对象。
      A.单层锁示例:
    Singleton* Singleton::getInstance() { 
        Lock lock;      // scope-based lock, released automatically when the function returns 
        if (m_instance == NULL) { 
            m_instance = new Singleton; 
        } 
        return m_instance; 
    } 
      B.DCL示例:【单层锁存在高并发时效率低,DCL提出先检测单件指针m_instance是否已创建,减少大部分的锁;上锁后,再次检查m_instance 】
     
    Singleton* Singleton::getInstance() { 
    if(m_instance==NULL)
    {
      Lock lock;      // scope- based lock, released automatically when the function returns 
        if (m_instance == NULL) { 
            m_instance = new Singleton; 
        } 
    }
       
        return m_instance; 
    } 
    【DCL的风险】
    回顾下(或者学习下)   m_instance = new Singleton; 发生了什么:
      1.分配Singleton对象所需的内存
      2.为该内存区域执行构造函数
      3.m_instance指向该内存。
      一切都似乎没有什么问题,但是有时编译器喜欢把2和3替换下(先不管编译器出于什么目的)
    执行单例化构造( m_instance = new Singleton; )的顺序中,其他线程访问对象程序未加锁【lock一般不阻止CPU线程调度程序,只对俩个线程里同样上了同个锁的部分函数有阻塞作用】,直接访问会出故障【操作未定义的对象】,又不能所有地方都加锁--效率低。
    解决方法:在单例化构造中先构造给临时变量,再把临时变量赋值给单例化对象的指针,注意防止编译器优化,否则前功尽弃【当然,这种方式的弊端目前尚未考虑到】。
     
    Singleton* Singleton::getInstance() { 
       volatile Singleton* tmp = m_instance; 
        ...                     // insert memory barrier 
        if (tmp == NULL) { 
            Lock lock; 
            tmp = m_instance; 
            if (tmp == NULL) { 
                tmp = new Singleton; 
                ...             // insert memory barrier 
                m_instance = tmp; 
            } 
        } 
        return tmp; 
    } 
    【背景知识】
      2000年,一个JAVA高性能研究小组发布了一篇声明《双重检查锁定可能导致锁定无效》。
      2004年,Scott Meyers 和Andrei Alexandrescu联合发表了一篇名为《C++实现双重检查锁定存在严重缺陷
    【参考链接】
    知行合一
  • 相关阅读:
    PHP使用数据库永久连接方式操作MySQL的是与非
    php生成xml文件
    Ruby学习之类
    新增题目功能模块总结
    Ruby学习之类2
    smarty section循环成两列的问题
    jQuery validate插件初探
    Zend Framework学习之Zend_Config
    Zend Framework学习之Zend_Loader动态加载文件和类
    JS 删除字符串最后一个字符的方法
  • 原文地址:https://www.cnblogs.com/guiguzhixing/p/6052844.html
Copyright © 2020-2023  润新知