我知道MESI协议成功地保证了不同核心的内存(缓存)具有相同的视图。我的问题源于这样一个事实:在写入期间,MESI保证缓存专属于CPU,并且原子CMPXCHG只是在原子地比较和交换值。那么既然我们已经从MESI协议中得到了这个保证,为什么还需要使用LOCK指令来锁定缓存行呢?
我知道MESI协议成功地保证了不同核心的内存(缓存)具有相同的视图。我的问题源于这样一个事实:在写入期间,MESI保证缓存专属于CPU,并且原子CMPXCHG只是在原子地比较和交换值。那么既然我们已经从MESI协议中得到了这个保证,为什么还需要使用LOCK指令来锁定缓存行呢?
原子CMPXCHG仅在比较和交换值时具有原子性
不,缓存访问硬件并没有将CMPXCHG实现为单周期固有原子操作。它是由多个uop合成的,这些uop分别进行加载和存储。
如果常规的CMPXCHG是这样工作的,那么您的推理就是正确的。但是对于其他核心上的观察者来说,常规的CMPXCHG是不原子的。
lock cmpxchg
解码成多个 uops,从加载到存储保持缓存行“锁定”,将其转换为单个原子事务,就其他观察者而言。在系统中可以看到。(即延迟响应对该行的 MESI 无效或共享请求,直到存储提交)。它还使其成为完整的内存屏障。
add [mem], edx
相同,后者在load和store uops之间使用ALU进行加法运算。即它不是原子性的,除了在同一个核心中针对中断(因为中断只能发生在指令边界处)。
加载和存储各自是独立的原子性操作,但它们不是单一的原子RMW事务。如果另一个核心使我们的缓存行失效,并在我们的加载和存储之间存储新值,则我们的存储将覆盖其他存储。而且那个其他存储将出现在我们的加载和存储之间的全局操作顺序中,违反了“原子”的定义=不可分割。
add [mem], edx
不是原子操作,以及lock
如何使其成为原子操作。cmpxchg
而不使用lock
的用例。rep
-string指令的迭代都计为一个单独的可中断指令。聚集加载和分散存储也是可中断的,进度记录在掩码向量(或AVX512掩码寄存器)中。它们在实践中可能不会以这种方式实现,除了自动生成的异常之外。我认为没有其他的,上次讨论我们只能想到这些。 - Peter Cordes