使用 C++ 原子库,我应该使用啥内存顺序进行加载,然后进行比较交换?
Posted
技术标签:
【中文标题】使用 C++ 原子库,我应该使用啥内存顺序进行加载,然后进行比较交换?【英文标题】:Using the C++ atomic lib, what memory order(s) should I use for a load followed by a compare exchange?使用 C++ 原子库,我应该使用什么内存顺序进行加载,然后进行比较交换? 【发布时间】:2017-01-31 17:53:26 【问题描述】:例如,多个线程执行 update() 函数:
// Statically allocated
atomic<int> high_water0;
//...
void update(int meas)
int i;
bool replaced;
do
i = high_water.load(?);
if (i >= meas)
break;
replaced = high_water.compare_exchange_strong(i, meas, ?, ?);
while (!replaced);
// ...
(我正在尝试实现在多个线程中进行的单个测量的共享高水位标记。)
【问题讨论】:
【参考方案1】:compare_exchange_strong
相对于high_water
是原子的,无论您指定什么内存顺序。内存排序仅与 other 内存操作有关。这在很大程度上取决于其他线程需要查看high_water
的方式和时间。由于meas
仅在此线程中可见,因此无需考虑其他加载和存储。因此,memory_order_relaxed
是正确的。
作为辅助说明,compare_exchange_strong
将第一个参数替换为观察值,因此执行 load
是多余的。
int i = high_water.load(std::memory_order_relaxed);
while (i < meas
&& high_water.compare_exchange_strong(i,
meas,
std::memory_order_relaxed,
std::memory_order_relaxed
)
)
continue;
【讨论】:
while ( i < meas && ! high_water.compare_exchange_strong(…) ) ;
【参考方案2】:
我应该使用什么内存顺序进行加载,然后进行比较交换?
无法判断,因为您没有显示调用 update()
的代码。
如果您使用memory_order_relaxed
(或任何比默认值更弱的东西),那么在某些平台上,围绕该调用的内存操作的重新排序是真实存在的。
high_water
实际上可能用于在线程之间同步数据。 如果您不担心这些可能的重新排序,那么std::memory_order_relaxed
很好。
一般来说,对于这些类型的操作,我不会使用比默认 (std::memory_order_seq_cst
) 更弱的排序。
由于std::compare_exchange_strong
是一个读取-修改-写入 (RMW) 操作,根据定义,它是昂贵的,因为它在核心之间同步原子的值,
改变内存顺序不会有太大的优势。至少在 X86 上,使用您的代码,编译器将为 std::memory_order_seq_cst
和 std::memory_order_relaxed
发出完全相同的目标代码。
旁注,由于您处于循环中,您可能希望使用compare_exchange_weak()
,这可能会虚假失败,但这是由循环处理的。
【讨论】:
以上是关于使用 C++ 原子库,我应该使用啥内存顺序进行加载,然后进行比较交换?的主要内容,如果未能解决你的问题,请参考以下文章
C++ 标准库 - 我应该啥时候使用它,啥时候不应该使用它?
C++ 原子内存顺序与诸如 notify() 之类的线程事件