为什么原子RMW指令的加载部分不能将早期存储传递到TSO(x86)内存一致性模型中的不相关位置?

为什么原子RMW指令的加载部分不能将早期存储传递到TSO(x86)内存一致性模型中的不相关位置?,x86,atomic,cpu-architecture,memory-barriers,memory-model,X86,Atomic,Cpu Architecture,Memory Barriers,Memory Model,众所周知,x86体系结构没有实现顺序一致性内存模型,因为使用了写缓冲区,所以可以进行存储->加载重新排序(稍后的加载可以提交,而早期的存储仍然驻留在写缓冲区中,等待提交到一级缓存) 在中,我们可以了解到Total Store Order(TSO)内存一致性模型中的读-修改-写(RMW)操作(该模型应该非常类似于x86): 。。。我们考虑 RMW作为负载,紧接着是存储。负载部分 由于TSO的订购规则,RMW无法通过早期加载。信息技术 一开始可能会出现RMW的负载部分 在写缓冲区中传递早期存储,但这

众所周知,x86体系结构没有实现顺序一致性内存模型,因为使用了写缓冲区,所以可以进行存储->加载重新排序(稍后的加载可以提交,而早期的存储仍然驻留在写缓冲区中,等待提交到一级缓存)

在中,我们可以了解到Total Store Order(TSO)内存一致性模型中的读-修改-写(RMW)操作(该模型应该非常类似于x86):

。。。我们考虑 RMW作为负载,紧接着是存储。负载部分 由于TSO的订购规则,RMW无法通过早期加载。信息技术 一开始可能会出现RMW的负载部分 在写缓冲区中传递早期存储,但这是不合法的。如果 RMW的加载部分通过一个较早的存储,然后是存储 部分RMW还必须通过较早的商店 因为RMW是一个原子对。但因为商店不是 允许在TSO中相互传递,RMW的负载部分不能 也可以通过较早的商店

好的,原子操作必须是原子的,即RMW访问的内存位置在RMW操作期间不能被其他线程/内核访问,但是,如果原子操作的早期存储通过加载部分与RMW访问的内存位置无关,那会怎么样?假设我们有以下两条指令(伪代码):

第一个存储被添加到写入缓冲区,并等待轮到它。同时,原子操作从另一个位置(甚至在另一个缓存线中)加载值,传递第一个存储,并在第一个存储之后将存储添加到写入缓冲区中。在全局内存顺序中,我们将看到以下顺序:

加载(原子的一部分)->存储(顺序)->存储(原子的一部分)


是的,从性能的角度来看,这可能不是一个最好的解决方案,因为我们需要将原子操作的缓存线保持在读写状态,直到写入缓冲区中的所有先前存储都提交为止,但是,性能考虑除外,是否存在任何违反TSO内存一致性模型的情况?我们是否允许RMW操作的加载部分将早期存储传递到不相关的位置?

您可以对不同地址的任何存储+加载对提出相同的问题:由于无序,加载可能在内部比旧存储更早执行执行。在X86中,这是允许的,因为:

可以使用较旧的存储将加载重新排序到不同的位置,但不能使用较旧的存储将加载重新排序到相同的位置

(来源:)

但是,在您的示例中,lock perfix会阻止这种情况,因为(来自同一组规则):

锁定的指令有一个总的顺序

这意味着锁将强制执行内存屏障,如mfence(事实上,一些编译器使用锁定操作作为屏障)。这通常会使CPU停止加载的执行,直到存储缓冲区耗尽,迫使存储首先执行

因为我们需要为原子操作保留缓存线 读写状态,直到写入缓冲区中的所有前面的存储被删除为止 承诺,但性能方面的考虑除外


如果您在执行与L阻止的操作具有相同性质的操作S时持有锁L,即存在可以被L阻止(延迟)的S和可以被L阻止(延迟)的S,则您有造成死锁的方法,除非您保证是唯一执行该操作的参与者(这将使整个原子变得毫无意义)。

如果您使用的是指令对(加载链接-存储条件)要实现原子增量操作,我看不出您建议的顺序有任何错误。但是,如果它是一条指令,那么它是不可能的,因为原子的加载部分变成了一个微操作,我们正在尝试混合操作和微操作,这可能不是一个好主意。@IsuruH在x86上它是一条单指令。但是s有什么问题呢uch mixing?Micro load op不等待以前的存储,而是从缓存中获取值,而Micro store op只是将结果放入写缓冲区。@x86 RMW上的IsuruH操作使用
lock
前缀来实现,前缀在执行原子指令期间可以将缓存线保持在M状态指令失效,锁被释放,因此,是的,将RMW操作的存储部分放在写缓冲区中会违反操作的原子性,因为从存储被放置到写入缓存时,任何其他内核都可以访问旧值。因此,它特别回答了我的问题,尽管它是r是一个实现细节,而不是TSO的概念限制。谢谢!!你的评论和@Leeor回答解释了为什么这不能做到。但是在我看来,从技术上讲,你可以允许在原子操作的读写之间耗尽另一个缓存线的存储。我对微操作的知识有点有限,所以我不确定如何对指令的部分进行重新排序,对我来说,重新排序发生在指令级别。@IsuruH AFAIK,即使没有CPU对指令进行实际的重新排序,这种“重新排序”也可能发生。即使您有一个标量CPU,只有一条管道,并且为了提交,您只需要立即从缓存或写入缓冲区加载值(如果它包含到所需位置的最新存储),但将存储推送到写入缓冲区,从而延迟它们。在这种情况下,存储->加载内存操作的全局顺序将更改,即使它们是微操作。感谢您提供的链接。根据我在“A Primer…”中阅读的内容,我错误地得出结论,x86上RMW操作的原子性(由于使用了
),因此无法重新排序
store int32 value in 0x00000000 location
atomic increment int32 value in 0x10000000 location