如果我有
std::atomic<uint64_t> guard;
// ...
if (std::atomic_compare_exchange_strong(
&guard, &kExpected, kValue,
std::memory_order_acquire, std::memory_order_relaxed)) {
int foo = *non_atomic_thing;
// ...
}
我知道在non_atomic_thing讀取guard. 但是是否有可能在寫入之前對其進行重新排序?也就是說,如果其他執行緒讀取guard,std::memory_order_acquire觀察到它不等于kValue,然后寫入它,這是資料競爭嗎?
(cppreference.com 對此不是很清楚,但具有相同語意的 Rust 的檔案明確表示,獲取僅適用于加載部分,而發布僅適用于存盤:“使用 Acquire 作為成功排序使得存盤此操作的一部分 放松“)
如果這是真的,我怎么能告訴其他執行緒在我閱讀它時不要覆寫我的值?
uj5u.com熱心網友回復:
C 標準在這一點上有點模糊。但是他們可能的意圖以及在許多實作中實際發生的情況是,您的非原子讀取可以在寫入之前重新排序。請參閱出于排序目的,原子讀取-修改-寫入操作是一個還是兩個?.
但是,對于通常的鎖定習慣來說,這不是問題,也不會導致資料競爭。在獲取鎖時,很容易將基本操作視為“鎖定”值的存盤,它告訴其他執行緒該鎖是我們的,他們不能擁有它。但實際上,重要的是“解鎖”值的負載。這證明鎖屬于我們的執行緒。讀-修改-寫操作的原子性保證在我們重置它之前沒有其他執行緒會加載該值,因此我們可以安全地進入臨界區,即使我們存盤的“鎖定”值直到直到一段時間以后。
您可以想象這發生在LL/SC 架構上。假設加載鏈接完成并回傳“解鎖”值。store-conditional 還沒有完成,它可能會失敗,以防其他一些內核訪問了 lock 變數并且我們失去了對它的獨占所有權。但是,與此同時,我們可以對非原子變數執行推測加載,并理解除非 SC 成功,否則它不會退出。如果 SC 發生故障,則必須重做 LL/SC 對,在這種情況下,我們的非原子負載也將被重做。因此,當我們最終獲得成功時,非原子負載將在 LL 之后可見,但可能在 SC 之前。
為了從 C 記憶體排序規則中了解這是如何遵循的,讓我們考慮一個更充實的示例:
std::atomic<int> lock{0};
int non_atomic;
void reader() {
int expected = 0;
if (lock.compare_exchange_strong(expected, 1,
std::memory_order_acquire, std::memory_order_relaxed)) {
int local = non_atomic;
// ...
lock.store(0, std::memory_order_release);
}
}
void writer() {
int expected = 0;
if (lock.compare_exchange_strong(expected, 2,
std::memory_order_acquire, std::memory_order_relaxed)) {
non_atomic = 42;
// ...
lock.store(0, std::memory_order_release);
}
}
讀-修改-寫操作的原子性承諾來自 C 20 [atomics.order p10]:
原子讀-修改-寫操作應始終讀取在與讀-修改-寫操作關聯的寫之前寫入的最后一個值(按修改順序)。
的修改順序為lock總順序。僅當兩個比較交換讀取值 0 時才會進入臨界區。加載的 0reader在修改順序中必須緊跟 1,加載的 0writer必須緊跟 2。所以必須出現 0兩次。因此 的修改順序lock必須是0 1 0 2 0或0 2 0 1 0。
如果是0 1 0 2 0,則第二個 0 必須來自 中的發布存盤reader。它不能來自 中的存盤writer,因為它必須在修改順序中位于 2 之后(因為writer0 的存盤在其 2 的存盤之后排序;這是寫-寫一致性,[intro.races p15])。因此,acquire load inwriter讀取順序中的第二個 0,這是由 release store in 放入的reader,因此它們同步。這確保了對non_atomicin的訪問reader發生在訪問 in 之前writer,并且沒有資料競爭。
如果是0 2 0 1 0,則邏輯相反,訪問 inwriter發生在訪問 in 之前reader;再次沒有資料競賽。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/482314.html
上一篇:無鎖的定義
