我最近在阅读有关Compare和Swap原子动作(CMPXCHG,.NET的Interlocked.CompareExchange,无论如何).
我理解它是如何在内部工作的,以及如何从客户端使用它.
我无法弄清楚的是,何时会有人使用CAS?
维基百科说:
CAS用于实现信号量和互斥量等同步原语,同样是更复杂的无锁和无等待算法.
那么,任何人都可以给我一个更通用的真实世界用例,其中包含CAS使用的代码和描述吗?
这个问题与语言无关,因此任何语言都可以(基于C语言或x86程序集首选).
谢谢!
许多C++ 11 CAS操作(例如,的atomic_compare_exchange_weak
,atomic_compare_exchange_strong
)取两个指针和值,即,是这样的:
bool atomic_compare_exchange(T* pointer, T* expected, // pseudodeclaration!
T desired);
Run Code Online (Sandbox Code Playgroud)
相比之下,来自Microsoft,gcc和Intel的CAS操作都采用一个指针和两个值:
long InterlockedCompareExchange(long* pointer, long desired, // Microsoft
long expected);
int __sync_bool_compare_and_swap (T* pointer, T expected, // gcc and
T desired); // Intel
Run Code Online (Sandbox Code Playgroud)
为什么C++ 11 CAS函数需要两个指针和一个值,而不是看起来更传统的一个指针和两个值?
我正在寻找一些很好的实际例子,说明ABA问题导致多线程代码出现问题.
执行原子比较和交换指令时,并发代码中会出现ABA问题.如果线程在执行比较和交换之前立即中断,则第二个线程可能会更改比较和交换的目标从其初始值A更改为不同的值B.如果它然后将值更改回A在第一个线程恢复之前,尽管目标值发生了变化,但compare-and-swap仍会成功.
在许多情况下,ABA不是问题.以共享引用计数为例:即使refcount同时更改,我们也没有问题,只要我们永远不会从已经下降到0的refcount增加.所以我们显然只对目标是否匹配感兴趣交换时的预期价值,而不是过去的变化.
在维基百科页面具有从ABA遭受无锁栈实现的例子,但我个人没有碰上在生产代码的问题为止.我只是好奇是否有人有一些很好的战争故事来分享ABA.
由于Integer类也是不可变类,我们知道不可变类是线程安全的,因此需要Atomic Integer.我很迷惑 .这是因为读取和写入不可变对象不必是原子的,而原子整数的读写是原子的.这意味着原子类也是线程安全的.
这个问题不是关于它们之间的区别 - 我知道什么是虚假故障以及为什么它会发生在LL/SC上.我的问题是,如果我使用的是intel x86并使用java-9(build 149),为什么它们的汇编代码有区别?
public class WeakVsNonWeak {
static jdk.internal.misc.Unsafe UNSAFE = jdk.internal.misc.Unsafe.getUnsafe();
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
Holder h = new Holder();
h.setValue(33);
Class<?> holderClass = Holder.class;
long valueOffset = UNSAFE.objectFieldOffset(holderClass.getDeclaredField("value"));
int result = 0;
for (int i = 0; i < 30_000; ++i) {
result = strong(h, valueOffset);
}
System.out.println(result);
}
private static int strong(Holder h, long offset) {
int sum = 0;
for (int i = 33; i < 11_000; ++i) { …
Run Code Online (Sandbox Code Playgroud) 我已经有这个问题了很长一段时间,试图阅读大量资源并了解正在发生的事情 - 但我仍然未能很好地理解为什么事情就是这样.
简单地说,我想测试如何CAS
将执行VS synchronized
在争,而不是环境.我提出了这个JMH
测试:
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class SandBox {
Object lock = new Object();
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder().include(SandBox.class.getSimpleName())
.jvmArgs("-ea", "-Xms10g", "-Xmx10g")
.shouldFailOnError(true)
.build();
new Runner(opt).run();
}
@State(Scope.Thread)
public static class Holder {
private long number;
private AtomicLong atomicLong;
@Setup
public void setUp() {
number = …
Run Code Online (Sandbox Code Playgroud) 您将如何使用嵌入式机器代码(假设,例如,x86架构)在C中编写一个执行原子比较和交换整数值的函数?如果它仅针对i7处理器编写,它可以更具体吗?
翻译是作为内存栅栏,还是仅仅确保在比较和交换中包含的内存位置上的排序关系?与记忆围栏相比,它的成本是多少?
谢谢.
等待和通知看起来像是在线程之间传递的消息,如果这是真的,则必须有用于缓冲这些消息的队列.如果是这样,那么必须有用于向队列添加消息和从队列中删除消息的原子操作,每个侦听这些消息的Java线程也必须有一个帮助线程吗?
很高兴听到你的想法.
java concurrency synchronization message-queue compare-and-swap
在Intel的文档称
该指令可以与
LOCK
前缀一起使用,以允许指令以原子方式执行.
我的问题是
可以CMPXCHG
用内存地址操作吗?从文档看来似乎没有,但任何人都可以确认只能在寄存器中使用实际的VALUE,而不是内存地址吗?
如果CMPXCHG
不是原子级和高级语言级CAS必须通过LOCK CMPXCHG
(带LOCK
前缀)来实现,那么引入这样一条指令的目的是什么?
C++ 11中有两个原子CAS操作:atomic_compare_exchange_weak
和atomic_compare_exchange_strong
.
根据cppreference:
允许函数的弱形式虚假地失败,即,即使它们是相等的,也可以表现为*obj!=*.当比较和交换处于循环中时,弱版本将在某些平台上产生更好的性能.当一个弱的比较和交换需要一个循环而一个强大的那个不需要时,强者更可取.
以下是使用弱版本的示例,我认为:
do {
expected = current.value();
desired = f(expected);
} while (!current.atomic_compare_exchange_weak(expected, desired));
Run Code Online (Sandbox Code Playgroud)
有人可以给出比较和交换不在循环中的示例,以便强版本更可取吗?
compare-and-swap ×10
atomic ×4
concurrency ×4
java ×3
c ×2
c++ ×2
c++11 ×2
x86 ×2
assembly ×1
atomic-long ×1
c# ×1
java-8 ×1
java-9 ×1
jmh ×1
jvm ×1
jvm-hotspot ×1