如何保证在存储发生之前加载完成?

How to guarantee that load completes before store occurs?

在下面的代码中,如何确保 ptr 在 *ptr 成为 loaded/assigned/"extracted" 之后才递增?

extern int arr[some_constexpr]; // assume pre-populated
extern int* ptr; // assume points to non-atomic arr
int a = *ptr;
// want "memory barrier/fence" here
++ptr;

原子指针能确保正确ordering/sequencing吗?

#include <atomic>

extern int arr[some_constexpr];
extern std::atomic<int*> ptr;
int a = *(ptr.load());
// implicit "memory barrier" achieved here by use of atomics?
ptr.store(ptr + 1);

这与两个线程之间共享的无锁队列有关。我想在更新指针之前确保与指针关联的数据不是lost/corrupted。

根据 Herb Sutter 的 talk(我强烈建议您尝试理解这些内容),例如请参阅时间 36:25-45:25,OP 中给出的原子示例足以确保在 ptr 递增之前分配 a

这是因为递增 ptr 是一个存储(因为它正在被写入),因此 "release" 给定默认内存顺序 std::memory_order_seq_cst (但也适用于*_acq_rel*_release 内存顺序)。这意味着在 ptr 的 increment/store/release 之前发生的任何事情都不能被重新排序为在 ptr 的 increment/store/release 之后发生,无论是由编译器、处理器、and/or 缓存.

除了原子 load/stores 隐含的内存栅栏外,不需要显式内存栅栏,而且在谈话中实际上不鼓励它们。

ptrstd::atomic<int*>++ptrptr++ptr.fetch_add(1, std::memory_order_acq_rel)时确保没有preceding/followingloads/stores得到重新排序 past/before 此操作。

++ptrptr++ 本质上是 ptr.fetch_add(1, std::memory_order_seq_cst) 并且 std::memory_order_seq_cst 几乎总是矫枉过正(无法给出不是的例子)。

更高效的 reader是:

int arr[some_constexpr];
std::atomic<int*> ptr;

int* p = ptr.load(std::memory_order_acquire);
int element = *p;
ptr.store(p + 1, memory_order_release);

以上就是boost::lockfree::spsc_queue的基本实现方式。


作为旁注,boost::lockfree::spsc_queue 是真实的 wait-free (strongest non-blocking guarantee of progress) queue. What push/pop operations do is 1 relaxed load, 1 acquire load and 1 release store and it is fundamentally not possible to implement a single-producer-single-consumer queue faster than that (sans implementation quality defects) with FIFO order guarantee. It is often used as a benchmark for all other queues。你可能想看看它。