C ++ 11的新机器模型允许多处理器系统可靠地工作。重组指示。
正如 Meyers和Alexandrescu 指出“简单”双重检查锁定模式实现在C ++ 03中并不安全
Singleton* Singleton::instance() {
if (pInstance == 0) { // 1st test
Lock lock;
if (pInstance == 0) { // 2nd test
pInstance = new Singleton;
}
}
return pInstance;
}
他们在their article中表明,无论你作为程序员做什么,在C ++ 03中,编译器都有太多的自由:允许以一种你可以不能重新排列指令的方式确保您最终只使用Singleton
的一个实例。
我现在的问题是:
Lock
)时,现在看起来这个Singleton模式的安全C ++ 11实现是什么样的?答案 0 :(得分:5)
如果pInstance
是常规指针,则代码具有潜在的数据竞争 - 指针上的操作(或任何内置类型,就此而言)不能保证是原子(编辑:或者很好) -ordered)
如果pInstance
是std::atomic<Singleton*>
并且 Lock
在内部使用std::mutex
来实现同步(例如,如果Lock
实际上是std::lock_guard<std::mutex>
),代码应该是数据竞争免费。
请注意,您需要 显式锁定和原子pInstance
才能实现正确的同步。
答案 1 :(得分:4)
由于静态变量初始化现在保证是线程安全的,因此Meyer的单例应该是线程安全的。
Singleton* Singleton::instance() {
static Singleton _instance;
return &_instance;
}
现在您需要解决主要问题:代码中有一个Singleton。
编辑:基于我在下面的评论:与其他实施相比,此实施有一个主要缺点。如果编译器不支持此功能会发生什么?编译器将发出线程不安全的代码,甚至不发出警告。如果编译器不支持新接口,那么带锁的其他解决方案甚至都不会编译。这可能是不依赖此功能的一个很好的理由,即使是单身人士以外的其他事情。
答案 2 :(得分:1)
C ++ 11不会改变双重检查锁定实现的含义。如果你想进行双重检查锁定工作,你需要建立适当的内存屏障/栅栏。