如何实现std :: atomic :: load

时间:2015-02-15 08:24:15

标签: c++ c++11 concurrency

假设我想实现一个自己的std :: atomic类型(当然我不想要,我只是出于好奇而问)。我该如何实现加载方法?我的猜测类似于以下内容(m_mutex是用于锁定操作的互斥锁,m_object是原子当前持有的对象:

T& load() {
    std::lock_guard<std::mutex> lck(m_mutex);

    return m_object;
}

显然,这不起作用,因为在调用a.load().doSomething()时,对doSomething的调用不会受到保护,因为m_object它已经从load返回并且没有被load保护再次锁定。

我想问两个问题:

  1. 如何实现正确的加载版本?
  2. 使用互斥锁而不是使用无锁数据结构来实现{{1}}的简单技术是什么?

2 个答案:

答案 0 :(得分:1)

  

如何实现正确的加载版本?

template <typename T>
class atomic {
public:
  static_assert(std::is_trivially_copyable<T>(),
                "atomic<T> requires trivially copyable T");

  // ...

  // Ignores the memory ordering parameter and always provides
  // sequential consistency. This is *correct*, but possibly
  // sacrifices performance.
  T load(std::memory_order) const noexcept {
    std::lock_guard<std::mutex> guard{mtx_};
    return t_;
  }

private:
  std::mutex mtx_;
  T t_;
};
  

使用互斥锁而不是使用无锁数据结构实现负载的简单技术是什么?

c ++中的无锁数据结构是使用无锁原子对象实现的。在标准C ++的范围内,无法实现无锁原子对象;他们需要来自编译器内在函数和/或特定于平台的内联汇编的支持,以便通过适当的排序保证来执行原子内存操作。在您选择的标准库中查看std::atomic的实现,以获取许多血腥细节。

答案 1 :(得分:1)

  

显然,这不会起作用,因为在打电话时   a.load()。doSomething()对doSomething的调用不受保护   因为m_object它已经从加载返回而没有被保护   锁定守卫了。

这是此接口不可避免的副作用,任何实现都无法更改。如果您不仅要加载它,还要保护它上面的其他随机功能,那么这就是一个完全不同的鱼。

如果您认为std::atomic这是安全的,那就不是。