我認爲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