CAS是一个像旋转一样的循环吗?

时间:2017-11-30 09:09:09

标签: java c++ jvm

当我阅读sun.misc.Unsafe.Java的代码时,我遇到了一个问题。

CAS是一个像旋转一样的循环吗?

起初,我认为CAS只是一种低生存的原子操作。但是,当我尝试找到函数compareAndSwapInt的源代码时,我发现这样的cpp代码:

jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) {
    assert(sizeof(jbyte) == 1, "assumption.");
    uintptr_t dest_addr = (uintptr_t)dest;
    uintptr_t offset = dest_addr % sizeof(jint);
    volatile jint* dest_int = (volatile jint*)(dest_addr - offset);
    jint cur = *dest_int;
    jbyte* cur_as_bytes = (jbyte*)(&cur);
    jint new_val = cur;
    jbyte* new_val_as_bytes = (jbyte*)(&new_val);
    new_val_as_bytes[offset] = exchange_value;
    while (cur_as_bytes[offset] == compare_value) {
        jint res = cmpxchg(new_val, dest_int, cur);
        if (res == cur) break;
            cur = res;
        new_val = cur;
        new_val_as_bytes[offset] = exchange_value;
    }
    return cur_as_bytes[offset];
}

我在这个原子功能中看到“何时”和“休息”。

这是旋转方式吗?

相关代码链接:

http://hg.openjdk.java.net/jdk8u/jdk8u20/hotspot/file/190899198332/src/share/vm/prims/unsafe.cpp

http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/07011844584f/src/share/classes/sun/misc/Unsafe.java

http://hg.openjdk.java.net/jdk8u/jdk8u20/hotspot/file/55fb97c4c58d/src/share/vm/runtime/atomic.cpp

3 个答案:

答案 0 :(得分:4)

CAS单个操作,返回值10,意味着此操作已成功或不成功,因为您正在执行{ {1}}您希望此操作成功,因此操作会重复进行,直到它正常工作。

我认为你也混淆了compareAndSwapInt,这基本上意味着做一些事情,而这个值是" 1" (例如);所有其他线程一直等到这个值为零(通过spin lock),这实际上意味着某个线程完成了工作并释放了锁(这称为compareAndSwap语义)

答案 1 :(得分:4)

CAS操作不是旋转,它是硬件级别的原子操作。在x86和SPARC处理器CAS上只有一条指令,它支持intlong个操作数。

确实使用单个cmpxchgl / {在x86上生成Atomic::cmpxchg int / long 重载{3}}指示。

您正在查看的内容是Atomic::cmpxchg单一 byte 重载,它适用于CAS指令的限制,以模拟CAS <\ n强> byte 级别。它是通过为与int位于同一地址的byte执行CAS,然后只检查一个byte并重复CAS,如果因为更改而导致CAS失败其他3个字节。比较和交换仍然是原子的,有时需要重新尝试,因为它覆盖了比必要更多的字节。

答案 2 :(得分:0)

例如,CAS通常是一个硬件指令,就像整数加法或比较一样(只是更慢)。指令本身可以分解为所谓的微码的几个步骤,并且可能确实包含低级循环或阻塞等待另一个处理器组件。但是,这些是处理器体系结构的实现细节。还记得CS中的任何问题都可以通过添加另一层间接来解决吗?这也适用于此。 Java中的原子操作实际上可能涉及以下层:

  1. Java方法签名。
  2. 实现它的C(++)JNI方法。
  3. C(++)“编译器内在”,例如GCC的__atomic_compare_exchange
  4. 实际的处理器指令。
  5. 实现此指令的微码。
  6. 所述微代码使用的附加层,例如高速缓存一致性协议等。
  7. 除非两种情况适用,否则我的建议不要担心所有这些都有效:

    • 由于某种原因,它工作。这可能是由于平台错误造成的。
    • 太慢了。

    单元测试可以帮助您识别前一种情况。基准测试可以帮助您识别后一种情况。但应该指出的是,如果Java提供给您的CAS很慢,那么您可能无法自己编写更快的CAS。因此,在这种情况下,最好的办法是更改数据结构或数据流,以进一步减少所需的线程同步量。