双重检查锁定:栅栏和原子

时间:2015-11-30 09:51:01

标签: c++ c++11 visual-c++

所以我做了一些阅读:https://en.wikipedia.org/wiki/Double-checked_lockinghttp://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;
}

如果我在加载/存储中用适当的内存顺序替换栅栏,我的意思是什么呢?

1 个答案:

答案 0 :(得分:1)

两个结构之间的差异在同一网站上的后续文章中进行了解释:Acquire and Release Fences Don't Work the Way You'd Expect。基本上,围栏保证在围栅之后所有原子商店将在围栏之前的所有商店“之前”可见。具有memory_order_release参数的商店仅对商店指令所关注的商店商店提供此类保证。

在您的示例中,您只有一个原子m_instance,因此这两个构造在功能上是等效的,没有围栏的构造可能更具性能。