21

我读过 x86 的 INC 指令不是原子的。我的问题是怎么来的?假设我们在 x86-64 上递增一个 64 位整数,我们可以用一条指令来完成,因为 INC 指令同时适用于内存变量和寄存器。那么它为什么不是原子的呢?

4

3 回答 3

21

为什么会这样?处理器内核仍然需要读取存储在内存位置的值,计算它的增量,然后将其存储回来。读取和存储之间存在延迟,同时另一个操作可能会影响该内存位置。

即使是乱序执行,处理器内核也足够“聪明”,不会绊倒自己的指令,也不会负责在时间间隙内修改此内存。但是,另一个内核可能发出了修改该位置的指令,DMA 传输可能影响了该位置,或者其他硬件以某种方式触及了该内存位置。

于 2012-04-11T16:07:01.500 回答
19

现代 x86 处理器作为其执行管道的一部分,将 x86 指令“编译”成较低级别的操作集;英特尔将这些 uOps 称为 AMD rOps,但归根结底是某些类型的单个 x86 指令由 CPU 中的实际功能单元分几个步骤执行。
例如,这意味着:

INC EAX

像单个“迷你操作”一样执行uOp.inc eax(让我这么称呼它-它们没有暴露)。
对于其他操作数,情况会有所不同,例如:

INC DWORD PTR [ EAX ]

低级分解虽然看起来更像:

uOp.load tmp_reg, [ EAX ]
uOp.inc tmp_reg
uOp.store [ EAX ], tmp_reg

因此不是原子执行的。另一方面,如果您在前面加上LOCK INC [ EAX ],这将告诉管道的“编译”阶段以不同的方式分解,以确保满足原子性要求。

这样做的原因当然是别人提到的——速度;如果不是总是需要的话,为什么要使某些东西成为原子的并且必然会变慢?

于 2012-04-11T16:59:42.123 回答
1

除非您需要,否则您真的不想要有保证的原子操作,来自Agner Fog软件优化资源instruction_tables.pdf (1996 – 2017):

带有 LOCK 前缀的指令有很长的延迟,这取决于缓存组织和可能的 RAM 速度。如果有多个处理器或内核或直接内存访问 (DMA) 设备,则所有锁定的指令都将锁定高速缓存行以进行独占访问,这可能涉及 RAM 访问。一个 LOCK 前缀通常花费超过一百个时钟周期,即使在单处理器系统上也是如此。这也适用于带有内存操作数的 XCHG 指令。

于 2012-04-11T16:51:44.677 回答