-
概念
- 程序的生命周期内只有一个实例的存在
-
场景
- 日志记录器、数据库连接池、线程池等
-
实现
#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] 保证共享资源在竞争场景下的可见性。