【问题标题】:Why doesn't the instruction reorder issue occur on a single CPU core?为什么在单个 CPU 内核上不会出现指令重排序问题?
【发布时间】:2016-02-27 16:36:45
【问题描述】:

来自post

在单个 CPU 内核上进行时间切片的两个线程不会遇到重新排序问题。单个核心始终知道自己的重新排序,并将正确解决所有自己的内存访问。然而,多个核心在这方面独立运行,因此不会真正了解彼此的重新排序。

为什么在单个 CPU 内核上不会出现指令重排序问题?本文不作解释。

示例
以下图片选自Memory Reordering Caught in the Act:

记录如下:

我认为记录的指令也会导致单个 CPU 出现问题,因为 r1r2 都不是 1

【问题讨论】:

    标签: multithreading memory multiprocessing cpu instructions


    【解决方案1】:

    单个核心始终知道自己的重新排序,并将正确解决自己的所有内存访问。

    单个 CPU 核心确实重新排序,但它知道它自己的重新排序,并且可以巧妙地假装它不是。因此,事情进展得更快,没有奇怪的副作用。

    然而,多个核心在这方面独立运行,因此不会真正了解彼此的重新排序。

    当一个 CPU 重新排序时,其他 CPU 无法对此进行补偿。想象一下,如果 CPU #1 正在等待对变量 A 的写入,那么它会从变量 B 中读取。如果 CPU#2 写入变量 B,那么变量 A 就像代码所说的那样,不会出现问题。如果 CPU#2 重新排序以首先写入变量 A,则 CPU#1 不知道并尝试在变量 B 有值之前读取它。这可能会导致崩溃或任何“随机”行为。 (英特尔芯片有更多的魔力让这种情况不会发生)

    在单个 CPU 内核上对两个线程进行时间切片不会遇到重新排序问题。

    如果两个线程都在同一个 CPU 上,那么写入发生的顺序无关紧要,因为如果它们被重新排序,那么它们都在进行中,并且 CPU 不会真正切换,直到两者已写入,在这种情况下,它们可以安全地从其他线程中读取。

    例子

    如果代码在单核上出现问题,则必须重新排列来自进程 1 的两条指令被进程 2 中断并在两条指令之间执行。但是如果在它们之间被打断,它知道它必须中止它们,因为它知道它自己的重新排序,并且知道它处于危险状态。因此,它要么按顺序执行它们,要么在切换到进程 2 之前同时执行它们,或者在切换到进程 2 之前不执行任何操作。所有这些都避免了重新排序问题。

    【讨论】:

    • 对于“Two threads being timesliced on a single CPU core won't run into a reordering problem.”,我在 OP 中添加了“EDIT”部分。你能帮忙解释一下吗?提前致谢!
    【解决方案2】:

    有多种效果在起作用,但它们被建模为一个效果。更容易对它们进行推理。是的,现代核心已经自行重新排序指令。但是它维护它们之间的逻辑流,如果两条指令之间存在相互依赖关系,那么它们将保持有序,因此程序的逻辑不会改变。发现这些相互依赖关系并防止指令过早发出是执行引擎中重新排序缓冲区的工作。

    这个逻辑是可靠的并且可以依赖,如果不是这样,几乎不可能编写程序。但是内存控制器不能提供同样的保证。它具有让多个处理器访问同一共享内存的令人羡慕的工作。

    首先是预取器,它提前从内存中读取数据,以确保在读取指令执行时数据可用。确保核心不会因为等待读取完成而停止。问题是,由于内存被提前读取,它可能是在预取完成和读取指令执行之间被另一个内核更改的陈旧值。对于外部观察者来说,它看起来像是提前执行的指令。

    还有存储缓冲区,它获取写入指令的数据,然后将其延迟写入内存。后来,在指令执行之后。确保内核不会停止等待内存总线写周期完成。对于外部观察者来说,它看起来就像是延迟执行的指令。

    将预取器和存储缓冲区的效果建模为指令重排序效果非常方便。您可以轻松地将其写在一张纸上并推断副作用。

    对于内核本身来说,预取器和存储缓冲区的影响是完全良性的,并且对它们视而不见。只要没有另一个内核也在改变内存内容。单核机器总是有这样的保证。

    【讨论】:

    • 那么OP中的EDIT部分不会出现在单核CPU机器上?
    • 你必须删除右栏。现在处理器 1 不再关心写入发生在读取之前还是之后。它只会关心 X 和 Y 是否是相同的内存位置。重新排序缓冲区已经解决了这个问题。
    • 抱歉,您能详细说明一下吗?
    • @HansPassant 这确实很有帮助。我刚刚有一个后续问题 - 所以当我们说重新排序时,它实际上并不是处理器重新排序指令,只是在外部观察者看来重新排序?就像你说的那样 - 读取指令没有优先于后一条指令,只是预取器更早地提取了它?
    • @ustulation:不,乱序执行确实可以以与程序顺序不同的顺序开始执行指令。但核心维持其指令按程序顺序执行的错觉(对于线程本身)。例如理论上,加载必须等待所有较早的存储地址已知,因此它们可以判断是否需要等待并将数据转发到存储缓冲区,或者它们是否可以访问 L1d 缓存。实际上,CPU 可以动态预测这不会发生,如果发生则回滚。顺便说一句,Hans 还指出,没有 OoO exec 也可以进行内存重新排序
    猜你喜欢
    • 2020-03-31
    • 2021-12-02
    • 2020-11-18
    • 2013-06-08
    • 2021-05-28
    • 2019-05-17
    • 1970-01-01
    • 2016-12-27
    相关资源
    最近更新 更多