【问题标题】:Understanding synchronization with multiple processors了解与多个处理器的同步
【发布时间】:2016-05-01 08:07:37
【问题描述】:

在 JCIP 第 15.2 B 节中,Goetz 提到,在现代处理器中,有一组指令,如 比较和交换 (CAS),它们允许我们执行非阻塞更新操作。

他特别说

CAS 有三个操作数 - 一个要操作的内存位置 V,预期的 旧值 A,新值 B。CAS 原子地将 V 更新为新值 B, 但前提是 V 中的值与预期的旧值 A 匹配。

现在考虑一个多处理器系统。如果两个不同的处理器尝试在完全相同的时间比较和交换同一内存位置,会发生什么?

处理器彼此不知道。这种情况如何处理?

【问题讨论】:

标签: java multithreading


【解决方案1】:

CAS 操作最终依赖于特定的硬件指令,因此实际实现是特定于硬件的。如果您想了解详细信息,则需要检查您正在运行的特定架构。

  • 在最流行的 x86 架构上,您可以将 CAS 操作视为使用锁,但在硬件中的粒度要细得多。

    • 例如实现 CAS 操作的一种方法是使用LOCK CMPXCHGLOCK 是一个指令前缀,可确保在伴随指令的持续时间内独占访问相应的内存位置。在这种情况下,附带的指令是CMPXCHG,它可以将给定内存位置的值作为一条指令进行比较和交换。

    • 当您从几个不同的线程执行myAtomicInt.compareAndSet(0, 1) 并导致来自几个不同的处理器的LOCK CMPXCHG 时,一个幸运的处理器将首先获得排他性并成功执行其操作。对该内存位置的锁定访问是可线性化的,因此稍后将获得独占性的其余处理器将导致其 CAS 失败(除非交错更改引入了 ABA problem)。

    • 仍然可以省略内存总线锁定(请参阅 Intel® 64 和 IA-32 架构中的 8.1.4 Effects of a LOCK Operation on Internal Processor Caches 软件开发者手册

  • 另一种执行 CAS 操作的硬件方法是 LL/SC(加载链接/条件存储)​​,它使用略有不同的机制和不同的特性。

    • 粗略地说,它将 CAS 分为两部分 - 初始加载和条件存储,如果在初始加载和存储之间相关内存发生变化,它会丢弃存储。这可以让您避免 ABA 问题,但它具有不同的可扩展性特征。

    • Here's 使用 LDREXSTREX 指令在 ARM 中使用 LL/SC 的示例。

  • 像 SPARC 这样的一些体系结构没有专用的 CAS 指令。在它们上,需要将 CAS 实现为指令和最终内存屏障的组合。

【讨论】:

  • 内存总线锁定仍然可以省略 怎么可能?我认为是内存总线锁定为 CPU 提供了对某些内存位置的独占访问权。这样其他 CPU 就会阻塞,直到第一个 CPU 完成。
  • 查看我在该声明之后立即提供的链接。简而言之,如果写入处理器对其缓存中的该内存位置具有独占访问权,则它可以避免锁定总线,而是依靠缓存一致性协议来确保操作的原子性。
  • 如果写入处理器可以独占访问其缓存中的该内存位置 听起来有点混乱。这就是我无法理解您所说的原因:假设我们有 CPU,每个 CPU 都有一些缓存和缓存一致性协议。如果其中一个 CPU 请求对某个内存位置进行独占访问以执行某些操作,它(取决于缓存一致性协议)可能会对其缓存中的值执行操作,并稍后将更改刷新到共享内存。我的理解现在接近真实了吗?
【解决方案2】:

处理器彼此不知道。

我很确定他们知道其他处理器,看看 MSI 协议...

https://en.wikipedia.org/wiki/MSI_protocol

有更现代的 MSI 变体,即 MESI 等专门处理这个问题。想象一个世界,CPU 可以在没有机制确保数据在 CPU 之间保持一致的情况下改变数据。

计算机科学中只有两件难的事情:缓存失效、命名事物和因一个错误而关闭。

【讨论】:

    【解决方案3】:

    处理器彼此不知道。

    处理器什么都不知道,它们只是芯片上的硅。

    如果两个不同的处理器尝试在同一时间在同一内存位置进行比较和交换,会发生什么?

    如果 CPU 的高速缓存对高速缓存行具有独占访问权限,则它可以直接执行更新。如果它没有独占访问权限。 L2 缓存一致性总线从另一个 CPU 的缓存中获取它,或者从 L3 缓存中获取它,然后它可以执行或不执行操作。 CAS 的不同之处在于它不会长时间阻塞。它可以返回false 表示它无法获取缓存行,但是调用它就足够了,处理器应该在将来的某个时间点获取它。

    这种情况如何处理?

    简而言之,L2 缓存一致性总线传输此信息并确保线程安全操作按应有的方式工作。

    【讨论】:

    • 让我澄清一下。因此,如果我们有争用,CAS 无论如何都会阻塞。但是这种阻塞不被认为是具有上下文切换和调度开销的“真正的阻塞”,对吗?
    • @DmitriiBundin 操作系统不参与,它只尝试一次获取缓存行,否则返回false。
    【解决方案4】:

    每个进程都有自己的内存,而对于内部通信,进程确实使用共享内存。在共享内存的情况下,我们需要在该共享内存中同步读/写。根据报价:

    CAS 具有三个操作数 - 用于操作的内存位置 V, 预期旧值 A 和新值 B。CAS 自动将 V 更新为 新值 B,但前提是 V 中的值与预期的旧值匹配 值 A。

    因为这是原子的,不仅对单个处理器而且对多个处理器都是原子的。这里的原子性是在总线上实现的。 CAS 锁定总线以保证操作的原子性。

    要深入了解这一切的工作原理以及使用哪些算法来确保原子性,请参阅8.1.3 Multiprocessor Synchronization

    【讨论】:

      猜你喜欢
      • 2011-12-15
      • 2020-03-03
      • 2018-01-19
      • 1970-01-01
      • 2023-03-09
      • 2014-12-17
      • 2018-04-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多