zoukankan      html  css  js  c++  java
  • Singleton单例模式

    模式定义

      保证一个类只能生成一个实例对象。

    单线程版本

     1 class Singleton{
     2 private:
     3     // 私有化构造函数和拷贝构造函数
     4     Singleton();
     5     Singleton(const Singleton& other);
     6 public:
     7     // 静态对象指针和静态获取对象指针函数
     8     static Singleton* getInstance();
     9     static Singleton* m_instance;
    10 };
    11 // 初始化
    12 Singleton* Singleton::m_instance=nullptr;
    13 
    14 //线程非安全版本
    15 Singleton* Singleton::getInstance() {
    16     if (m_instance == nullptr) {
    17         m_instance = new Singleton();
    18     }
    19     return m_instance;
    20 }
    21 
    22 //线程安全版本,但锁的代价过高
    23 Singleton* Singleton::getInstance() {
    24     Lock lock;
    25     if (m_instance == nullptr) {
    26         m_instance = new Singleton();
    27     }
    28     return m_instance;
    29 }

    多线程版本

    class Singleton{
    private:
        // 私有化构造函数和拷贝构造函数
        Singleton();
        Singleton(const Singleton& other);
        mutex  mymutex;  //互斥量
    public:
        // 静态对象指针和静态获取对象指针函数
        static Singleton* getInstance();
        static Singleton* m_instance;
    };
    // 初始化
    Singleton* Singleton::m_instance=nullptr;    

    线程安全版本,但锁的代价过高

    1 //线程安全版本,但锁的代价过高
    2 Singleton* Singleton::getInstance() {
    3     unique_lock<mutex> mylock(mymutex);
    4     if (m_instance == nullptr) {
    5         m_instance = new Singleton();
    6     }
    7     return m_instance;
    8 }

    双检查锁版本(会出错)

     1 //双检查锁
     2 // 但由于内存读写reorder不安全, 编译器的优化有关
     3 // 在汇编层面m_instance = new Singleton()语句可能的执行顺序是
     4 // 先分配内存地址,再执行构造函数,再赋值给内存,导致第二次检查结果为false,但是这时对象还没创建
     5 Singleton* Singleton::getInstance() {
     6     // 这里的检查,在已经创建了单例对象后,就没有必要加锁
     7     if(m_instance==nullptr){
     8         Lock lock;
     9         // 在检查一次是为了避免两个线程都通过了第一个检查,都会创建的对象的情况
    10         if (m_instance == nullptr) {
    11             m_instance = new Singleton();
    12         }
    13     }
    14     return m_instance;
    15 }

    原子操作版本

     1 //C++ 11版本之后的跨平台实现 (volatile)
     2 // 或者使用原子操作
     3 std::atomic<Singleton*> Singleton::m_instance;
     4 std::mutex Singleton::m_mutex;
     5 
     6 Singleton* Singleton::getInstance() {
     7     Singleton* tmp = m_instance.load(std::memory_order_relaxed);
     8     std::atomic_thread_fence(std::memory_order_acquire);//获取内存fence
     9     if (tmp == nullptr) {
    10         std::lock_guard<std::mutex> lock(m_mutex);
    11         tmp = m_instance.load(std::memory_order_relaxed);
    12         if (tmp == nullptr) {
    13             tmp = new Singleton;
    14             std::atomic_thread_fence(std::memory_order_release);//释放内存fence
    15             m_instance.store(tmp, std::memory_order_relaxed);
    16         }
    17     }
    18     return tmp;
    19 }

      综上,在多线程中,推荐使用原子操作版。

  • 相关阅读:
    Json对象与Json字符串互转(4种转换方式)
    Web.config配置文件详解
    jQuery BlockUI Plugin Demo 6(Options)
    jQuery BlockUI Plugin Demo 5(Simple Modal Dialog Example)
    jQuery BlockUI Plugin Demo 4(Element Blocking Examples)
    jQuery BlockUI Plugin Demo 3(Page Blocking Examples)
    jQuery BlockUI Plugin Demo 2
    <configSections> 位置引起的错误
    关于jQuery的cookies插件2.2.0版设置过期时间的说明
    jQuery插件—获取URL参数
  • 原文地址:https://www.cnblogs.com/chen-cs/p/13278002.html
Copyright © 2011-2022 走看看