单例模式之线程安全

22 阅读2分钟
  • 概念

    • 程序的生命周期内只有一个实例的存在
  • 场景

    • 日志记录器、数据库连接池、线程池等
  • 实现

    #include <iostream>
    #include <mutex>
    #include <boost/noncopyable.hpp>using namespace std;
    ​
    // 版本一
    // 创建即初始化-eager initialize
    // 不过需要提前初始化。但是从生产环境考虑,单例模式必须创建,同时需要系统预热。
    // 因此该版本也具有一定的适用性。
    class Singleton : public boost::noncopyable{
    private:
        shared_ptr<Singleton> sp_instance;
        
    private:
        Singleton() = default;
        
    public:
        // 智能指针的析构函数需要对象的析构函数的访问权限
        ~Singleton() = default;
        
        static weak_ptr<Singleton> GetInstance() {
            return sp_instance;
        }
    };
    ​
    shared_ptr<Singleton> Singleton::sp_instance(new Singleton);
    ​
    // 以下几个版本为用时创建,Lazy模式。
    // 版本二
    // 会出现写放大(A进程创建智能指针A并赋值给静态单例变量,
    // 此时发生进程切换,B进程创建智能指针B并赋值给单例变量,因此A进程创建的智能指针A自动销毁)。
    // 总的来说,能够正确创建并返回对象,但是初始会多创建一次浪费资源
    class Singleton : public boost::noncopyable{
    private:
        Singleton() = default;
        
    public:
        // 智能指针需要调用
        ~Singleton() = default;
        
        static weak_ptr<Singleton> GetInstance() {
            static shared_ptr<Singleton> sp_singleton = 
                shared_ptr<Singleton> (new Singleton());
            return sp_singleton;
        }
    };
    ​
    // 版本三
    // 先上锁->并发退化成串行。
    // 在写-读场景下并发能力弱。适用于写-写场景。
    class Singleton : public boost::noncopyable{
    private:
        shared_ptr<Singleton> sp_instance;
        mutex_t mutex;
        
    private:
        Singleton() = default;
        
    public:
        // 智能指针需要调用
        ~Singleton() = default;
        
        static weak_ptr<Singleton> GetInstance() {
            mutex.lock();   // RALL
            if (sp_instance == nullptr)
                sp_instance = shared_ptr<Singleton> (new Singleton());
            return sp_singleton;
        }
    };
    ​
    // 版本四
    // DCL+volatile关键字->版本三的优化。
    // 通过volatile关键字防止最外层判断出现未完全初始化对象,通过内层加锁保证过程的互斥性。
    // 适合写-读场景。
    class Singleton : public boost::noncopyable{
    private:
        static volatile shared_ptr<Singleton> instance;
        static std::mutex mutex;
    ​
    private:
        Singleton() = default;
    ​
    public:
        ~Singleton() {}
        
        static weak_ptr<Singleton> GetInstance() {
            if (instance == nullptr) {
                mutex.lock();
                if (instance == nullptr) {
                    instance = shared_ptr<Singleton> (new Singleton());
                }
            }
            return instance;
        }
    };
    ​
    ​
    int main() {
        auto ptr_singleton = Singleton::GetInstance();
        // do something...
    }
    

    [volatile]  保证共享资源在竞争场景下的可见性。