编辑:在进一步缩小了真正让我困惑的内容之后,进行了实质性的编辑。我一直在努力使这个问题的一般概念保持不变,以保持所收到的伟大答案的相关性。
发布于 2018-04-16 00:09:35
重新:你的编辑,这似乎是一个新的问题:对,存储转发“违反”一致性。一个核心比任何其他核心都能看到它自己的商店。存储缓冲区不连贯。
x86内存排序规则要求加载按程序顺序变得全局可见,但允许内核在数据变得全局可见之前从其自己的存储区加载数据。它不需要假设它等待并检查内存顺序错误的推测,就像它在其他情况下比内存模型说的更早地进行加载一样。
x86能否重新订购一个包含了它的更大负载的窄存储?是存储缓冲区+存储转发违反通常的内存排序规则的一个具体例子。参见Linus发布的邮件列表的这个收藏品,它解释了存储转发对内存排序的影响(以及它如何意味着建议的锁定方案不起作用)。
如果根本没有一致性,您将如何原子地增加一个共享计数器,或者实现其他原子读-修改-写入操作,这些操作对于实现锁或直接在无锁代码中使用至关重要。(见对于'int‘,num++可以是原子的吗?)。
同时,多个线程中的lock add [shared_counter], 1不会丢失对实际x86的任何计数,因为lock前缀使核心从加载一直保持缓存行的独占所有权,直到存储提交到L1d (从而成为全局可见的)。
没有连贯缓存的系统将允许每个线程增加自己的共享计数器的副本,然后内存中的最终值将来自最后刷新该行的线程。
即使在其他负载/存储发生时,允许不同的缓存长期保存同一行相互冲突的数据,并且跨越内存屏障,也会允许各种奇怪的情况发生。
这也违反了这样一种假设,即一个纯粹的存储很快就会被其他内核看到。如果根本没有一致性,那么内核可以继续使用共享变量的缓存副本。因此,如果您希望读者注意到更新,那么在每次读取共享变量之前,都必须使用clflush ,这使得普通情况下的开销很大(因为自上次检查以来没有人修改数据)。
MESI就像一个推送通知系统,而不是强迫每个读者在每次读取时重新验证他们的缓存。
在没有修改数据结构的情况下,RCU (读-拷贝-更新)之类的内容允许阅读器(与单线程相比)具有零开销(与单线程相比)。见https://lwn.net/Articles/262464/和https://en.wikipedia.org/wiki/Read-copy-update。其基本思想是,作者不是锁定数据结构,而是复制整个内容,修改副本,然后更新共享指针以指向新版本。因此,读者总是完全没有等待;他们只是取消引用一个(原子)指针,数据在他们的L1d缓存中保持热。
硬件支持的一致性是非常有价值的,几乎每个共享内存SMP架构都使用它.即使是内存排序规则比x86弱得多的ISAs,如PowerPC,也使用MESI。
https://stackoverflow.com/questions/49843709
复制相似问题