所以我做了一些阅读:https://en.wikipedia.org/wiki/Double-checked_locking和http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/。我找到了使用它的代码
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;
Singleton* Singleton::getInstance() {
Singleton* tmp = m_instance.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(m_mutex);
tmp = m_instance.load(std::memory_order_relaxed);
if (tmp == nullptr) {
tmp = new Singleton;
std::atomic_thread_fence(std::memory_order_release);
m_instance.store(tmp, std::memory_order_relaxed);
}
}
return tmp;
}
并且有一件事我不清楚。它是否与不带栅栏的代码有所不同?
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;
Singleton* Singleton::getInstance() {
Singleton* tmp = m_instance.load(std::memory_order_acquire);
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(m_mutex);
tmp = m_instance.load(std::memory_order_acquire);
if (tmp == nullptr) {
tmp = new Singleton;
m_instance.store(tmp, std::memory_order_release);
}
}
return tmp;
}
如果我在加载/存储中用适当的内存顺序替换栅栏,我的意思是什么呢?
答案 0 :(得分:1)
两个结构之间的差异在同一网站上的后续文章中进行了解释:Acquire and Release Fences Don't Work the Way You'd Expect。基本上,围栏保证在围栅之后所有原子商店将在围栏之前的所有商店“之前”可见。具有memory_order_release
参数的商店仅对商店指令所关注的商店商店提供此类保证。
在您的示例中,您只有一个原子m_instance
,因此这两个构造在功能上是等效的,没有围栏的构造可能更具性能。