从此post:
在单个CPU核心上进行时间间隔的两个线程不会遇到重新排序问题。单个核心始终知道它自己的重新排序,并将正确解析所有自己的内存访问。然而,多个核心在这方面独立运作,因此无法真正了解彼此的重新排序。
为什么单个CPU内核不会出现指令重新排序问题?这篇文章没有解释。
示例:
以下图片是从Memory Reordering Caught in the Act中选取的:
以下记录:
我认为录制的指令也会导致单个CPU出现问题,因为r1
和r2
都不是1
。
答案 0 :(得分:2)
单个核心始终知道自己的重新排序,并将正确解决所有自己的内存访问。
单个CPU核心 重新排序,但它知道它自己的重新排序,并且可以做巧妙的技巧来假装它不是。因此,事情变得更快,没有奇怪的副作用。
然而,多个核心在这方面独立运作,因此不会真正了解彼此的重新排序。
当CPU重新排序时,其他CPU无法对此进行补偿。想象一下,如果CPU#1正在等待对variableA的写入,那么它从variableB读取。如果CPU#2写入变量B,那么变量A就像代码所说的那样,没有问题发生。如果CPU#2重新排序以首先写入variableA,则CPU#1不知道并尝试在变量B具有值之前从其读取。这可能导致崩溃或任何“随机”行为。 (英特尔芯片有更多的魔力使这不会发生)
在单个CPU内核上对两个线程进行时间划分不会遇到重新排序问题。
如果两个线程都在同一个CPU上,那么写入的顺序并不重要,因为如果它们被重新排序,那么它们都在进行中,并且CPU将不会真正切换到两个写的,在这种情况下,他们可以安全地从另一个线程中读取。
实施例
如果代码在单个内核上出现问题,则必须重新排列进程1中的两条指令和被进程2中断并在两条指令之间执行。但如果它们之间中断,它就知道它必须中止它们,因为它知道它自己的重新排序,并且知道它处于危险状态。所以它要么按顺序执行,要么在切换到进程2之前执行它们,或者在切换到进程2之前都不执行它们。所有这些都避免了重新排序问题。
答案 1 :(得分:2)
有多种效果在起作用,但它们被建模为一个效果。更容易推理它们。是的,现代核心已经自行重新订购指令。但是它维持它们之间的逻辑流,如果两个指令之间存在相互依赖关系,那么它们就会保持有序,因此程序的逻辑不会改变。发现这些相互依赖关系并防止指令过早发布是执行引擎中重新排序缓冲区的工作。
这种逻辑是可靠的,可以依赖,如果不是这样的话,编写程序几乎是不可能的。但是内存控制器无法提供相同的保证。它让令人难以置信的工作就是让多个处理器访问同一个共享内存。
首先是预取程序,它提前从内存中读取数据,以确保在读取指令执行时数据可用。确保核心不会停止等待读取完成。由于存储器被早期读取的问题,它可能是一个陈旧的值,在预取完成和读取指令执行之间由另一个核心改变。对于外部观察者来说,它看起来像早期执行的指令。
存储缓冲区,它接收写指令的数据并将其懒惰地写入存储器。之后,执行指令后。确保核心不会停止等待内存总线写周期完成。对于外部观察者来说,它看起来就像执行的指令一样。
将预取器和存储缓冲区的效果建模为指令重新排序效果非常方便。你可以轻松地将它写在一张纸上并推断出副作用。
对于核心本身来说,预取器和存储缓冲区的效果完全是良性的,并且它们对它们一无所知。只要没有其他核心也在改变内存内容。具有单核的机器始终具有这种保证。