如何将两个值相乘并以原子方式存储结果?

How to multiply two values and store the result atomically?

假设我的代码中有以下全局变量:

std::atomic<uint32_t> x(...);
std::atomic<uint32_t> y(...);
std::atomic<uint32_t> z(...);

我的任务是将 x 和 y 相乘,然后将结果存储在 z:

z = x * y

我知道在每个对象上调用 store() 和 load() 的幼稚方法是完全错误的:

z.store(x.load() * y.load()); // wrong

这样我执行了三个独立的原子指令:另一个线程可能会滑过并同时更改其中一个值。

我可以选择比较和交换 (CAS) 循环,但它只保证将 z 的旧值与新值 (x*y) 交换的原子性:我我仍然不确定如何在单个原子步骤中执行整个操作。

我也知道将 xyz 包装在一个结构中并使其成为原子在这里是不可行的,因为该结构不适合在单个 64 位寄存器。编译器会在引擎盖下使用锁(如果我在这里错了,请纠正我)。

这个问题只能用互斥锁解决吗?

I'm still not sure how to perform the whole operation in a single, atomic step.

只有当您的体系结构支持诸如“32 位原子乘法”之类的东西(并且您必须在 C++ 标准的设施之外进行它)或一个足够宽的原子来执行64 位上的 RMW 操作。

I'm also aware that wrapping x, y and z inside a struct and make it atomic is not feasible here, as the struct doesn't fit inside a single 64-bit register.

即使它们适合,您仍然需要执行 RMW 操作,因为无论如何您都不太可能有原子乘法。

Is this problem solvable only with a mutex?

如果您的架构支持 lock-free 64 位原子(检查 is_always_lock_free),您可以将 xy 放在一起并对其执行操作根据需要。

what if the variables were uint64_t instead, or the operation was way more complex like x * y * w * k / j?

假设您的体系结构没有 128 位 lock-free 原子,那么您无法以原子方式加载那么多数据。要么设计你的程序,使其不需要(完整的)操作是原子的,要么使用锁,要么寻求一种避免共享状态的方法。

请注意,即使您将某些操作视为原子操作,您也必须意识到在 SMP 系统中您无论如何都会对缓存层次结构施加压力。