|
|
旅途中的牛腩 · python ...· 6 月前 · |
|
|
长情的冲锋衣 · Java消息队列总结篇(ActiveMQ、R ...· 2 年前 · |
|
|
完美的排球 · npm设置同时从多个包源加载包的方法_nod ...· 2 年前 · |
|
|
个性的乌冬面 · angular - Parameter ...· 3 年前 · |
问题:new 操作符指令重排
C++ 98 表达单线程语义。而在多核多线程的情况下,若 cpu 指令重排,例如:对于 new 运算符的指令执行:分配内存、调用构造函数、返回指针。若发生 cpu 指令重排,会优化为分配内存、返回指针,却还没有调用构造函数初始化数据。此时,若有其他线程访问,可能造成程序的崩溃。
C++ 11:多线程语义,cpu 指令重排,提供同步原语:原子变量、内存屏障等
原子变量解决
memory_order_acuire
不能重排指令,
memory_order_release
松散指令,可以重排指令。
内存屏障(内存栅栏)解决
使用原子变量解决原子性、可见性、执行序
public: static Singleton * GetInstance() { Singleton* tmp = _instance.load(std::memory_order_acquire); if (tmp == nullptr) { std::lock_guard<std::mutex> lock(_mutex); tmp = _instance.load(std::memory_order_acquire); if (tmp == nullptr) { tmp = new Singleton; _instance.store(tmp, memory_order_release); atexit(Destructor); return tmp; static std::atomic<Singleton*> _instance; static std::mutex _mutex; std::atomic<Singleton*> Singleton::_instance; // 静态成员需要初始化 std::mutex Singleton::_mutex; // 互斥锁初始化改进:若构造函数中存在其他原子性操作,则可以使用松散的指令执行方式,提升运行速度。使用内存屏障,避免 tmp 指针在 new 操作未执行完就返回给用户。
问题:无论是否需要该类实例,都必须提前创建。
源自:C++ effective,C++ 11 magic static 特性,参考官方文档: 静态局部变量 static / thread local ,推荐使用。
因此,使用定义在栈上的局部静态变量保存单例对象,具备所有优点: