Qza*_*aac 6 c++ multithreading atomic lock-free c++11
当我无法弄清楚为什么需要特定的内存屏障时,我一直在本网站上查看无锁的单生产者/单消费者循环缓冲区。我已经仔细阅读了数百次关于内存顺序的标准规则,但我不明白我错过了什么。
通过这种实现,只有一个可以调用该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
}
Run Code Online (Sandbox Code Playgroud)
这是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;
}
Run Code Online (Sandbox Code Playgroud)
我理解为什么绝对需要theProducer (4)和 theConsumer (2)语句,这是因为我们必须确保一旦将看到存储的值,所有在by之前发生的写入都将是可见的副作用。(4) released storeProducerconsumer
我也明白为什么Consumer (4)需要这个语句,这是为了确保Consumer (3)在执行Consumer (4)存储之前执行加载。
问题
Producer (2)需要使用获取语义(而不是轻松)执行加载?是否要防止Producer (3) or (4)在条件之前(在编译时或运行时)被重新编码?我们需要证明
_array[current_tail] = item; // push(3)
Run Code Online (Sandbox Code Playgroud)
符合后执行( current_head == current_tail)
item = _array[current_head]; // pop(3)
Run Code Online (Sandbox Code Playgroud)
完成了。仅当单元格中的数据已复制到项目后,我们才能覆盖单元格
这
_head.load(std::memory_order_acquire) // push(2)
Run Code Online (Sandbox Code Playgroud)
同步于
_head.store(increment(current_head), std::memory_order_release); //pop(4)
Run Code Online (Sandbox Code Playgroud)
通过释放-获取排序:
一旦原子加载获取 ( push (2) ) 完成,在原子存储释放 ( pop(4) )之前发生的所有内存写入 ( pop(3) _head) 都会产生可见的副作用。_head
因此, push(2)完成后的生产者代码,保证可以看到pop(3)的结果。这意味着数据被复制到 item 并且此操作的结果对于Push(2)_array[current_head]之后的生产者代码可见,因此已经空闲。_array[current_head]
从加载描述的另一面来看-当前线程中的memory_order_acquire读取或写入 ( push(3) ) 在此加载之前不能重新排序。所以push(3)将在push(2)加载完成后执行,但此时pop(3)已经完成
item = _array[current_head]; //pop(3)
_head.store(increment(current_head), std::memory_order_release); //pop(4)
-----
_head.load(std::memory_order_acquire); //push(2)
_array[current_tail] = item; //push(3)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1811 次 |
| 最近记录: |