无锁环形缓冲区的boost示例中的内存排序

时间:2018-07-10 19:22:53

标签: c++ boost lock-free circular-buffer wait-free

当我阅读有关免等待环形缓冲区实现示例的boost原子时:

https://www.boost.org/doc/libs/1_66_0/doc/html/atomic/usage_examples.html#boost_atomic.usage_examples.example_ringbuffer

我想知道是否有必要在

使用memory_order_acquire
if (next_head == tail_.load(boost::memory_order_acquire))

似乎memory_order_relaxed也应该工作。我的论点是

 value = ring_[tail];

之前发生

tail_.store(next(tail), boost::memory_order_release)

在pop()调用中。因此我们确定在存储为push()之前,已读取了数据

 ring_[head] = value;

我在下面粘贴了整个boost示例代码,以方便参考。 谢谢!

#include <boost/atomic.hpp>

 template<typename T, size_t Size>
 class ringbuffer {
 public:
 ringbuffer() : head_(0), tail_(0) {}

 bool push(const T & value)
 {
    size_t head = head_.load(boost::memory_order_relaxed);
    size_t next_head = next(head);
    if (next_head == tail_.load(boost::memory_order_acquire))

//上面的tail_.load是否可以使用boost :: memory_order_relaxed?

    return false;
    ring_[head] = value;
    head_.store(next_head, boost::memory_order_release);
    return true;
 }
 bool pop(T & value)
{
    size_t tail = tail_.load(boost::memory_order_relaxed);
    if (tail == head_.load(boost::memory_order_acquire))
    return false;
   value = ring_[tail];
   tail_.store(next(tail), boost::memory_order_release);
   return true;
 }
 private:
   size_t next(size_t current)
   {
      return (current + 1) % Size;
   }
  T ring_[Size];
  boost::atomic<size_t> head_, tail_;

};

2 个答案:

答案 0 :(得分:1)

一个原因是顺序出现:

if(next_head == tail_.load(boost::memory_order_acquire))
    return false;
ring_[head] = value; // A non-atomic store.

memory_order_acquire确保以下非原子存储不会在tail_加载之前重新排序。

另一方面,

memory_order_relaxed不能阻止重新排序,因此在这里还不够。

(假设boost::memory_order等同于std::memory_order。)


Release-Acquire ordering

  

在强排序的系统(x86,SPARC TSO,IBM大型机等)上,大多数操作都是自动执行发布获取排序。对于此同步模式,不会发出其他CPU指令。仅会影响某些编译器优化(例如,禁止编译器将非原子存储移动到原子存储释放之外,或者禁止执行比原子负载获取早的非原子负载)。在弱序系统(ARM,Itanium,PowerPC)上,使用特殊的CPU负载或内存隔离指令。

答案 1 :(得分:0)

据我所知,tail_.load(boost::memory_order_acquire)中的push()head_.load(boost::memory_order_acquire)中的pop()都可以放宽并替换为xx.load(boost::memory_order_relaxed)