不做作业,为考试而学习。
我对问题陈述的最佳尝试:
假设线程调用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期间不可能更改*值。
答案 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的情况下仍然没有实际保证单个负载。