【发布时间】:2019-06-13 13:27:53
【问题描述】:
当我无法弄清楚为什么需要特定的内存屏障时,我一直在查看this website 上的无锁单一生产者/单一消费者循环缓冲区。 我已经仔细阅读了一百次the standard rules about memory order,但我不明白我错过了什么。
有了这个实现,只有一个可以调用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) 语句是绝对需要的,这是因为我们必须确保所有发生在(4) released storeProducer 之前的写入一旦consumer 看到存储的值,就会出现可见的副作用。
我也明白为什么需要Consumer (4) 语句,这是为了确保在执行Consumer (4) 存储之前执行Consumer (3) 加载。
问题
- 为什么
Producer (2)加载需要acquire semantic(而不是relaxed)执行?是为了防止Producer (3) or (4)在条件之前(编译时还是运行时)被重新排序?
【问题讨论】:
-
每个问题一个问题。
-
@πάνταῥεῖ 完成 ;)
标签: c++ multithreading c++11 atomic lock-free