我认为is_valid(A,B)可根据A.改变
在这种情况下,这是不是安全的 - 考虑以下序列:
- 线程1调用
is_valid(A, B)
,并得到真正的
- 线程2调用
is_valid(A, B)
并且变为真
- 线程1调用
__sync_sub_and_fetch(A, B)
变化A,并且A的新值表示is_valid(A, B)
现在是错误的。
- 线程2调用
__sync_sub_and_fetch(A, B)
即使它不应该因为is_valid(A, B)
现在是错误的。
您可能会感兴趣的比较交换操作。在这种情况下,你可以写这样的:
int oldValueOfA, newValueOfA;
do {
oldValueOfA = A;
__sync_synchronize(); // memory barrier; makes sure A doesn't get accessed after this line
if (!is_valid(oldValueOfA, B))
throw error;
newValueOfA = oldValueOfA - B;
} while(!__sync_bool_compare_and_swap(&A, oldValueOfA, newValueOfA));
你不能让两个操作原子,但你可以检测如果他们不是原子然后你可以再次尝试。
这是有效的,因为如果A
仍然不包含oldValueOfA
,__sync_bool_compare_and_swap
什么也不做,并返回false。否则,它将其设置为newValueOfA
并返回true。因此,如果它返回true,则在您忙于拨打is_valid
时,您知道其他人没有更改A
。如果它返回false,那么你还没有做任何事情,所以你可以自由地回去重试。
请注意is_valid
可能会被调用几次;这是相关的,如果它有副作用(如在屏幕上打印消息)。在这种情况下,你应该只使用一个互斥量。
感谢您的解释。所以在这种情况下我必须使用互斥锁?如果'is_valid'只是'return A> B;'或者是一个相当复杂的函数,需要数百条指令,那么有什么区别吗? – bbvan
@bbvan如果'is_valid'只是'return A> B;',你认为我描述的东西还是可以发生的吗?如果不是,为什么不呢?事实上,你问*建议*你没有真正想过我的解释。 – immibis
是的,我认为没有区别...但是我希望有一些像'sync_if_cmpgt_then_sub'这样的神奇的原子操作... – bbvan