如何保证在存储发生之前加载完成?
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 隐含的内存栅栏外,不需要显式内存栅栏,而且在谈话中实际上不鼓励它们。
当ptr
为std::atomic<int*>
、++ptr
或ptr++
或ptr.fetch_add(1, std::memory_order_acq_rel)
时确保没有preceding/followingloads/stores得到重新排序 past/before 此操作。
++ptr
或 ptr++
本质上是 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。你可能想看看它。
在下面的代码中,如何确保 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 隐含的内存栅栏外,不需要显式内存栅栏,而且在谈话中实际上不鼓励它们。
当ptr
为std::atomic<int*>
、++ptr
或ptr++
或ptr.fetch_add(1, std::memory_order_acq_rel)
时确保没有preceding/followingloads/stores得到重新排序 past/before 此操作。
++ptr
或 ptr++
本质上是 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。你可能想看看它。