众所周知,由于使用写缓冲区,x86体系结构不实现顺序一致性内存模型,因此可以进行存储 - >加载重新排序(以后的加载可以提交,而早期的存储仍然驻留在写入缓冲区中等待提交到L1缓存)。
在A Primer on Memory Consistency and Coherence中,我们可以阅读有关总存储顺序(TSO)内存一致性模型(应该与x86非常相似)的读 - 修改 - 写(RMW)操作:
......我们考虑一下 RMW作为负载,紧接着是商店。负载部分 由于TSO的订购规则,RMW无法传递早期负载。它 可能最初看起来RMW的负载部分可以 在写缓冲区中传递早期存储,但这不合法。如果 RMW的加载部分通过早期的商店,然后是商店 RMW的一部分也必须通过早期的商店 因为RMW是原子对。但因为商店不是 允许在TSO中相互传递,RMW的负载部分不能 通过早先的商店。
好的,原子操作必须是原子操作,即RMW操作期间RMW访问的内存位置不能由其他线程/核心访问,但是如果早期存储通过原子操作的加载部分而不是与RMW访问的内存位置有关?假设我们有以下几条指令(伪代码):
store int32 value in 0x00000000 location
atomic increment int32 value in 0x10000000 location
第一个存储被添加到写缓冲区并等待轮到它。同时,原子操作从另一个位置(甚至在另一个缓存行中)加载值,传递第一个存储,并在第一个存储之后将存储添加到写缓冲区中。在全局内存顺序中,我们将看到以下顺序:
加载(原子的一部分) - > store(ordinal) - >商店(原子的一部分)
是的,从性能的角度来看,它可能不是最佳解决方案,因为我们需要保持读写状态下原子操作的缓存行,直到写入缓冲区中的所有先前存储都被提交,但是,除了性能考虑之外,是否有任何违反TSO内存一致性模型的行为是否允许RMW操作的负载部分将早期存储传递到不相关的位置?
答案 0 :(得分:4)
您可以向不同的地址询问有关任何商店+加载对的相同问题:由于无序执行,加载可能比旧商店更早地执行。在X86中,这是允许的,因为:
负载可能会将较旧的商店重新排序到不同的位置,但不能与较旧的商店重新排序到同一位置
(来源:Intel 64 Architecture Memory Ordering White Paper)
但是,在您的示例中,锁定perfix会阻止这种情况,因为(来自同一组规则):
锁定的指令总订单
这意味着锁将强制执行内存屏障,就像mfence一样(实际上一些编译器使用锁定操作作为栅栏)。这通常会使CPU停止执行加载,直到存储缓冲区耗尽,迫使存储首先执行。
答案 1 :(得分:1)
因为我们需要保留原子操作的缓存行 读写状态,直到写缓冲区中的所有先前存储都为 承诺,但除了性能方面的考虑
如果您在进行与S阻止的操作具有相同性质的操作S时握住了锁L,则存在存在S'可以被L阻止(延迟)并且S可以被L阻止(延迟)。 ',那么您就有了造成僵局的秘诀,除非可以保证您是唯一这样做的演员(这会使整个原子事情变得毫无意义)。