【问题标题】:Advantages and disadvantages of CAS programming [closed]CAS编程的优缺点[关闭]
【发布时间】:2013-06-03 14:55:43
【问题描述】:

谁能给我总结一下比较和交换编程的优缺点? (例如多核 CPU 性能)

以下是 Java 中的示例:

/**
 * Atomically increments by one the current value.
 *
 * @return the updated value
 */
public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

=== 编辑===

请在单/核 CPU 中专门讨论这个问题。

【问题讨论】:

  • @Neyt:感谢您删除错误的标签,但请在有标签时添加正确的标签。有一个[compare-and-swap] 标签。
  • @PeterCordes 确实,没想到会有自己的标签,谢谢。
  • @Neyt:我不确定为什么 cmpxchg 也需要自己的标签,但 CAS 与 load-linked+store-conditional 是原子 RMW 操作的两个基本构建块;硬件通常提供一种或另一种。 en.wikipedia.org/wiki/Compare-and-swap 它确实带有特定于 CAS 的问题,例如 ABA 问题。因此,它不像硬件提供的每个可能的原子 RMW 都有标签那样随意(例如,x86 可以在没有 CAS 重试循环的情况下进行原子增量和各种其他事情。)

标签: java c++ lock-free compare-and-swap lockless


【解决方案1】:

优点:没有锁,因此没有死锁并且通常具有更好的可扩展性

缺点:饥饿的风险(除非算法也是免等待的,但一般情况并非如此)

edit:wait-free 算法在失去 CAS 比赛时会执行一些操作。而不是忙于尝试/启动。

【讨论】:

    【解决方案2】:

    只有在没有实现所需原子操作的内置语言的情况下,才在源代码中编写 CAS 重试循环。硬件(尤其是 x86)通常可以做得更好。

    Java 的 AtomicInteger 具有 getAndIncrement()incrementAndGet() 方法(至少从 Java 7 开始),这使得 JVM 可以轻松地将其 JIT 为 asm,这比实际的 CAS 重试更有效环形。这就像 C++11 的 std::atomic::fetch_add()。另见Practical uses for AtomicInteger

    在 x86 上,您希望您的 JVM 利用 x86 对该操作的硬件支持。如果您使用直接映射到它的函数而不是 CAS,则更有可能发生这种情况- 优化器必须努力优化成非循环实现的重试循环。

    (当多个 CPU 内核争用同一个高速缓存行时,locked 操作存在硬件总线/高速缓存仲裁;一次只有一个线程可以实际拥有高速缓存行并进行增量。您可能会说这是wait-free,即使“步骤”是时钟周期而不是 CPU 指令:locked 操作在任何给定系统上可能需要等待多长时间的上限可能较低,即使所有其他内核都在同一个缓存上敲击行。)

    ; possible x86 implementation of incrementAndGet() for a 32-bit integer
    ; which you'd hopefully get (after inlining and so on)
    
    mov    eax,1
    lock   xadd [mem], eax       ; atomically do [mem]+=eax, and put the old value in eax
    inc    eax                   ; old_value += 1 to get the new value
    ; result in EAX
    

    不需要循环。

    在 LL/SC 机器(大多数非 x86,如 ARM、PowerPC、MIPS)上,会有一个重试循环,但它不完全是 CAS。 LL/SC 机器上的 CAS 重试循环有额外的开销。很轻微,但是让JVM直接看到你想要的原子操作肯定更好。有关 CAS 与 LL/SC 的更多讨论,请参阅 Atomically clearing lowest non-zero bit of an unsigned integer。 CAS 循环可以在理论上优化为纯 LL/SC 循环。

    该问题也是您最好的选择(在 C++ 或 Java 源代码中)是 CAS 重试循环的示例,因为该语言没有执行您想要的操作的原子原语。 (任何通用硬件也没有)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多