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

时间:2019-07-07 10:46:24

标签: c++ multithreading concurrency atomic stdatomic

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

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位寄存器。编译器会在后台使用锁(如果我错了,请更正我)。

此问题只能通过互斥体解决吗?

1 个答案:

答案 0 :(得分:4)

  

我仍然不确定如何在单个原子步骤中执行整个操作。

仅当您的体系结构支持“ 32位原子乘法”(并且您必须在C ++标准的工具之外进行此操作)或足够宽的原子以执行RMW操作时,才可以这样做在64位上。

  

我还知道将xyz包装在一个结构中并使其原子化在这里是不可行的,因为该结构不适合单个64位寄存器。

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

  

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

如果您的体系结构支持无锁的64位原子(请检查is_always_lock_free),则可以将xy放在一起,并根据需要对其进行操作。 / p>

  

如果变量改为uint64_t还是操作像x * y * w * k / j一样复杂呢?

假设您的体系结构没有128位无锁原子,那么您就不能自动加载那么多数据。请设计您的程序,以使程序不需要原子操作就可以完成(完整)操作,使用锁或寻求避免共享状态的方法。

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