当我阅读有关免等待环形缓冲区实现示例的boost原子时:
我想知道是否有必要在
使用memory_order_acquireif (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_;
};
答案 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
。)
在强排序的系统(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)
。