AtomicIncrement using CompareAndSwap

AtomicIncrement using CompareAndSwap

本文关键字:CompareAndSwap using AtomicIncrement      更新时间:2023-10-16

不是家庭作业,为考试而学习。

我对问题陈述的最佳尝试

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

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条件检查之间更改(*值)吗?

我的教科书(第 10 页)说"反复尝试将值更新为新数量",但我看不出 *value 除了通过调用线程传递给 AtomicIncrement() 的原始值之外,我一定错过了一些东西。混淆来自于这样一个事实,即 CompareAndSwap 一开始应该是一个原子指令,所以在对 CompareAndSwap 的"调用"期间没有机会更改 *值。

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

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

问题 1.从这个线程加载*value到它调用CompareAndSwap*value可能已经被另一个线程更改了。这就是为什么循环是必要的。

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