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 }

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

  • 相关阅读:
    xcode修改默认头部注释(__MyCompanyName__) (转)
    ios7注意事项随笔
    二分查找(BinarySearch)
    选择排序(SelectionSort)
    插入排序(InsertionSort)
    堆排序(HeapSort)
    归并排序(MergeSort)
    快速排序(QuickSort)
    基本-正则表达式
    2.5亿个整数中找出不重复的整数
  • 原文地址:https://www.cnblogs.com/chen-cs/p/13278002.html
Copyright © 2011-2022 走看看