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