Skip to content

Latest commit

 

History

History
75 lines (62 loc) · 2.19 KB

10.单例模式.md

File metadata and controls

75 lines (62 loc) · 2.19 KB

单例模式 Singleton

动机

在软件系统中经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性以及良好的效率。

模式定义

保证一个类仅有一个实例,并提供一个该实例的全局访问点。

代码

class Singleton{
private:
    Singleton();
    Singleton(const Singleton& other);
public:
    static Singleton* getInstance();
    static Singleton* m_instance;
};

Singleton* Singleton::m_instance = nullptr;

// 非线程安全版本
Singleton* Singleton::getInstacne(){
    if(m_instance == nullptr){
        m_instance = new Singleton();
    }
    return m_instacne;
}

// 线程安全版本,但是锁的代价过高(假设 m_instance 不为 nullptr,多个线程同时读)
Singleton* Singleton::getInstacne(){
    Lock lock;
    if(m_instance == nullptr){
        m_instance = new Singleton();
    }
    return m_instacne;
}

// 双检查锁,但由于内存读写 reorder 不安全
Singleton* Singleton::getInstacne(){
    if(m_instance == nullptr){
        // 第二个 if 判断是防止两个线程同时运行到该行位置时,只有一个实例被创建
        Lock lock;
        if(m_instance == nullptr){
            m_instance = new Singleton();   // [指令级别可能会被reorder为1,3,2] 1. 分配内存;2.调用构造器; 3.内存地址给 m_instance
        }
    }
    return m_instacne;
}

//C++11 版本之后的跨平台实现(volatile)
std::atomic<Singleton*> Singleton::m_instance;
std::mux Singleton::m_mutex;
Singleton* Singleton::getInstacne(){
    Singleton* tmp = m_instacne.load(std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_acquire);    // 获取内存 fence
    if(tmp == nullptr){
        std::lock_guard<std::mutex> lock(m_mutex);
        tmp = m_instacne.load(std::memory_order_relaxed);
        if(tmp == nullptr){
            tmp = new Singleton();
            std::atomic_thread_fence(std::memory_order_release);    // 释放内存fence
            m_instance.store(tmp, std::memory_order_relaxed);
        }
    }
    return tmp;
}

题目