【发布时间】:2020-06-21 04:11:16
【问题描述】:
根据我对原子的理解,它们是特殊的汇编指令,可保证 SMP 系统中的两个处理器不能同时写入同一内存区域。例如,在 PowerPC 中,原子增量类似于:
retry:
lwarx r4, 0, r3 // Read integer from RAM location r3 into r4, placing reservation.
addi r4, r4, 1 // Add 1 to r4.
stwcx. r4, 0, r3 // Attempt to store incremented value back to RAM.
bne- retry // If the store failed (unlikely), retry.
但是,这并不能保护四个指令不被中断抢占,并且另一个任务被安排进来。为了防止抢占,您需要在输入代码之前执行中断锁定。
根据我对C++ atomics 的了解,他们似乎在需要时强制执行锁定。所以我的第一个问题是 -
- C++ 标准是否保证在原子操作期间不会发生抢占?如果是这样,我可以在标准中的哪个位置找到它?
我在我的英特尔 PC 上检查了atomic<int>::is_always_lock_free,它是true。根据我对上述装配块的假设,这让我感到困惑。在深入研究英特尔组件(我不熟悉)之后,我发现lock xadd DWORD PTR [rdx], eax 正在发生。所以我的问题是-
- 某些体系结构是否提供保证不抢占的原子相关指令?还是我的理解有误?
最后我想知道 compare_exchange_weak 和 compare_exchange_strong 语义 -
- 区别在于重试机制还是其他原因?
编辑:看完答案后,我又好奇一件事
- 原子成员函数操作
fetch_add、operator++等是强还是弱?
【问题讨论】:
-
无锁不保证不可抢占。您引用的 PowerPC 示例是无锁的,但仍然是可抢占的。 (1) C++ 不保证不可抢占的行为。正如您所指出的,某些处理器支持非抢占式读取-修改-写入操作,但并非全部,例如 PowerPC。 (2) 是的,一些架构确实支持非抢占式读-修改-写原子。 (3) 不同的是,weak 允许虚假失败。这符合 PowerPC 语义。
-
唯一的“弱”原子是
compare_exchange_weak。其他人无法发出失败信号,并且具有无条件的效果。在像 PowerPC 这样的 LL/SC 机器上,它们必须编译成像 CAS_strong 这样的重试循环。 (当然纯加载/纯存储除外,因为它们不是 RMW 操作,所以不需要重试循环即可。)