使用 C++ 原子库,我应该使用什么内存顺序进行加载,然后进行比较交换?

Using the C++ atomic lib, what memory order(s) should I use for a load followed by a compare exchange?

例如,多个线程执行 update() 函数:

// Statically allocated
atomic<int> high_water{0};
//...
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);
// ...

(我正在尝试实现在多个线程中进行的单个测量的共享高水位线。)

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;

what memory order(s) should I use for a load followed by a compare exchange?

无法判断,因为您没有显示调用 update() 的代码。 如果您使用 memory_order_relaxed (或任何比默认值更弱的东西),围绕该调用的内存操作的重新排序在某些平台上是真实的。 high_water其实可能是用来同步线程间的数据的。 如果您不担心那些可能的重新排序,那么std::memory_order_relaxed没问题。

一般来说,对于这类操作,我不会使用比默认 (std::memory_order_seq_cst) 更弱的顺序。 由于 std::compare_exchange_strong 是一个 Read-Modify-Write (RMW) 操作,根据定义它是昂贵的,因为它同步核心之间的原子值, 更改内存顺序不会有太大优势。至少在 X86 上,使用您的代码,编译器将为 std::memory_order_seq_cststd::memory_order_relaxed 发出完全相同的目标代码。

边注,因为你在一个循环中,你可能想使用 compare_exchange_weak(),这可能会虚假地失败,但这是由循环处理的。