使用CompareAndSwap的AtomicIncrement

时间:2017-03-30 15:20:41

标签: c++ c concurrency

不做作业,为考试而学习。

我对问题陈述的最佳尝试

假设线程调用AtomicIncrement,将指针传递给共享整数变量。没有指定另一个线程是否会修改此变量,但它是可能的。 Compare和swap的这种实现在成功交换时返回1,在失败时返回0(old!= value)

void AtomicIncrement(int *value, int amount) { 
    do { int old = *value; } // save old value 
    while (CompareAndSwap(value, old, old + amount) == 0); 
}

问题:

我真的不明白这里发生了什么。

代码执行“int old = * value;”的原因是因为另一个线程可以在do {}和while条件检查之间改变(* value)吗?

My textbook (page 10)说“反复尝试将值更新为新的数量”但是我没有看到*值除了通过调用线程传递给AtomicIncrement()的原始值之外的其他任何值,我必须是遗漏了什么。混淆来自于CompareAndSwap应该是一个开始的原子指令,因此在“调用”CompareAndSwap期间不可能更改*值。

1 个答案:

答案 0 :(得分:1)

如果没有临时变量或循环,您将运行CompareAndSwap(value, *value, *value + amount)。这不是原子的。评估函数的参数(在评估每个参数之间没有确定顺序)与函数调用本身之间有sequence point

此函数必须加载*value作为参数传递给CompareAndSwap。它还必须加载*value以便在表达式*value + account中使用,也可以作为参数传递。

问题1.在此线程加载*value的时间与调用CompareAndSwap的时间之间,*value可能已被另一个线程更改。这就是为什么循环是必要的。

问题2.无法保证编译器仅发出*value的单个负载。加载*value一次并将amount添加到本地副本是合法的,但加载*value两次也是合法的,一次用于第二个参数和一个用于第三个参数。如果发生这种情况,那么另一个线程可能在这些负载之间发生了更改*value。这就是使用临时变量的原因,尽管在没有memory barrier的情况下仍然没有实际保证单个负载。