我读过x86的INC指令不是原子的。我的问题是怎么来的?假设我们在x86-64上递增64位整数,我们可以用一条指令来完成,因为INC指令适用于内存变量和寄存器。那么为什么它不是原子的呢?
答案 0 :(得分:19)
为什么会这样?处理器内核仍然需要读取存储在存储器位置的值,计算它的增量,然后将其存储回来。读取和存储之间存在延迟,同时另一个操作可能会影响该存储位置。
即使执行无序,处理器内核也“足够智能”,不会跳过自己的指令,也不负责在时间间隔内修改此内存。但是,另一个核心可能已发出修改该位置的指令,DMA传输可能会影响该位置,或者其他硬件以某种方式触及该存储位置。
答案 1 :(得分: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 ]
前缀,那将告诉管道的“编译”阶段以不同的方式分解,以确保满足原子性要求。
其原因当然是其他人提到的 - 速度;为什么要做一些原子的东西,如果不总是需要的话,必然要慢一些?
答案 2 :(得分:1)
你确实不希望保证原子操作,除非你需要它,来自Agner Fog的Software optimization resources:instruction_tables.pdf(1996 - 2017):
具有LOCK前缀的指令具有长延迟,具体取决于缓存组织和可能的RAM速度。如果有多个处理器或核心或直接内存访问(DMA)设备 然后所有锁定的指令将锁定高速缓存行以进行独占访问,这可能涉及RAM访问。 LOCK前缀通常需要超过一百个时钟周期,即使在单处理器上也是如此 系统。这也适用于带有内存操作数的XCHG指令。