首页 > 解决方案 > 如何保证在存储发生之前加载完成?

问题描述

在下面的代码中,如何确保 ptr 在 *ptr 被加载/分配/“提取”之后才增加?

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;

原子指针会确保正确的排序/排序吗?

#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);

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

标签: c++multithreadingatomicmemory-barriers

解决方案


When ptris std::atomic<int*>, ++ptr, or ptr++orptr.fetch_add(1, std::memory_order_acq_rel)确保没有在此操作之前/之后的加载/存储重新排序。

++ptr, 或者ptr++本质上是ptr.fetch_add(1, std::memory_order_seq_cst)并且std::memory_order_seq_cst几乎总是过度杀伤(不能举一个不是的例子)。

更高效的单一阅读器是:

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是一个真正的无等待(最强的非阻塞进度保证)队列。push/pop操作所做的是 1次relaxed加载、1次acquire加载和 1release次存储,并且从根本上说不可能比具有 FIFO 顺序保证的速度更快地实现单生产者-单消费者队列(没有实施质量缺陷)。它通常用作所有其他队列的基准。你可能想调查一下。


推荐阅读