单例模式在C++中的使用:原子操作
原子操作
在 C++11 中将原子操作纳入了标准,我们可以通过标准提供的原子操作来处理该问题。
通过给原子变量设置 std::std::memory_order_xxx 来防止 CPU 的指令重排操作。
#include <atomic> #include <mutex> class Singleton { private: static std::atomic<Singleton*> s_instancePtr; static std::mutex s_mutex; public: static Singleton* instance() { Singleton* sin = s_instancePtr.load(std::memory_order_acquire); if (nullptr == s_instancePtr) { std::lock_guard<std::mutex> lock(s_mutex); sin = s_instancePtr.load(std::memory_order_relaxed); if (nullptr == s_instancePtr) { sin = new Singleton(); s_instancePtr.store(sin, std::memory_order_release); } } return sin; } private: // 省略构造函数的处理 }; std::atomic<Singleton*> Singleton::s_instancePtr; std::mutex Singleton::s_mutex;Meyers单例
其实还有一种简单的单例方式,那就是所谓的 Meyers 单例。
该方式在函数内部定义一个局部静态变量,并直接将该变量返回即可。
在 C++11 中保证了会以线程安全的方式初始化一个静态局部变量,因此可以放心使用。
static Singleton& instance() { static Singleton s_instance; return s_instance; }在《Effective C++》一书中提到:任何一种 non-const static 对象,不论它是 local 还是 non-local,在多线程环境下“等待某事发生”都会有麻烦。
处理这个麻烦的一种做法是:在程序的单线程启动阶段,手工调用所有 reference-returning 函数,这可能消除与初始化有关的“竞速形式”。
