Ign*_*ant 8 c++ concurrency multithreading atomic stdatomic
假设我的代码中包含以下全局变量:
std::atomic<uint32_t> x(...);
std::atomic<uint32_t> y(...);
std::atomic<uint32_t> z(...);
Run Code Online (Sandbox Code Playgroud)
我的任务是将x和y相乘,然后将结果存储在z中:
z = x * y
Run Code Online (Sandbox Code Playgroud)
我知道在每个对象上调用store()和load()的天真方法是完全错误的:
z.store(x.load() * y.load()); // wrong
Run Code Online (Sandbox Code Playgroud)
这样,我执行了三个单独的原子指令:另一个线程可能会滑过并同时更改其中一个值。
我可以选择比较交换(CAS)循环,但只能保证将旧值z
与新值(x*y
)交换时才具有原子性:我仍然不确定如何一次执行整个操作,原子步。
我也知道,包装x
,y
以及z
一个结构内,并使其原子是不可行这里,因为结构不适合一个64位寄存器内。编译器会在后台使用锁(如果我错了,请更正我)。
这个问题只能用互斥锁解决吗?
我仍然不确定如何在单个原子步骤中执行整个操作。
只有当您的体系结构支持“32 位原子乘法”(并且您必须在 C++ 标准设施之外执行此操作)或足够宽以在 64 位上执行 RMW 操作的原子时,才有可能这样做位。
我还知道,将
x
,y
和z
包装在结构内部并使其原子化在这里是不可行的,因为该结构不适合单个 64 位寄存器。
即使它们适合,您仍然需要执行 RMW 操作,因为无论如何您都不可能进行原子乘法。
这个问题只能用互斥锁来解决吗?
如果您的体系结构支持无锁 64 位原子(使用 进行检查is_always_lock_free
),您可以将x
和保留y
在一起并根据需要对其执行操作。
如果变量是
uint64_t
相反的,或者操作更复杂怎么办x * y * w * k / j
?
假设您的架构没有 128 位无锁原子,那么您无法以原子方式加载那么多数据。要么设计你的程序,使其不需要(完整的)操作从一开始就是原子的,使用锁或寻求一种避免共享状态的方法。
请注意,即使您将某些操作视为原子操作,您也必须意识到,在 SMP 系统中,您无论如何都会对缓存层次结构施加压力。