我一直在研究一个无锁单生产者/单消费者循环缓冲区,源自这个网站,但我不知道为什么需要特定的内存屏障。我已经仔细阅读了关于内存顺序的标准规则多次,但我还是不明白哪里出了问题。
这个实现中,只有一个唯一的线程可以调用
下面是
我明白为什么绝对需要
我也理解为什么需要
这个实现中,只有一个唯一的线程可以调用
push()
函数,另一个唯一的线程可以调用pop()
函数。下面是
Producer
代码:bool push(const Element& item)
{
const auto current_tail = _tail.load(std::memory_order_relaxed); //(1)
const auto next_tail = increment(current_tail);
if(next_tail != _head.load(std::memory_order_acquire)) //(2)
{
_array[current_tail] = item; //(3)
_tail.store(next_tail, std::memory_order_release); //(4)
return true;
}
return false; // full queue
}
这里是 Consumer
的代码:
bool pop(Element& item)
{
const auto current_head = _head.load(std::memory_order_relaxed); //(1)
if(current_head == _tail.load(std::memory_order_acquire)) //(2)
return false; // empty queue
item = _array[current_head]; //(3)
_head.store(increment(current_head), std::memory_order_release); //(4)
return true;
}
我明白为什么绝对需要
Producer (4)
和Consumer (2)
语句,这是因为我们必须确保所有在Producer
释放存储器的(4) released store
之前发生的写操作在consumer
看到存储的值时都能够被看到。我也理解为什么需要
Consumer (4)
语句,这是为了确保在执行Consumer (4)
存储操作之前,Consumer (3)
加载操作已经完成。
问题
- 为什么需要使用acquire semantic(而不是relaxed)来执行
Producer (2)
加载操作?这是为了防止编译时或运行时重新排序Producer (3)或(4)
之前的条件吗?