[英]Is is worth to declare a size_t as std::atomic if used across 2 threads?
我有一個size_t
變量,它由std::thread
更新並由另一個std::thread
讀取。
我知道我可以互斥保護讀取和寫入。 但是,如果我將size_t
設為std::atomic<size_t>
,它會是一樣的還是有益的?
是的,這是值得的。 事實上,如果多個線程使用同一個變量並且至少有一個正在寫入該變量,則必須使用std::atomic
或同步對非原子的訪問。 不遵守此規則是數據競爭未定義行為。
根據您對std::size_t
的使用,編譯器可以假設非原子和其他非同步變量不會從其他線程更改並相應地優化代碼。 這可能會導致 Bad Things™ 發生。
我通常的例子是一個使用非原子布爾值的循環:
// make keepRunning an std::atomic<bool> to avoid endless loop
bool keepRunning {true};
unsigned number = 0;
void stop()
{
keepRunning = false;
}
void loop()
{
while(keepRunning) {
number += 1;
}
}
在啟用優化的情況下編譯此代碼時,GCC 和 Clang 都只會檢查keepRunning
一次,然后開始無限循環。 有關生成的匯編器輸出,請參閱https://godbolt.org/z/GYMiLE 。
即他們將其優化為if (keepRunning) infinite_loop;
,將負載提升到環路之外。 因為它是非原子的,所以他們可以假設沒有其他線程可以編寫它。 有關同一問題的更詳細信息,請參閱多線程程序卡在優化模式但在 -O0 中正常運行。
請注意,此示例僅在循環體足夠簡單時才顯示錯誤。 然而,未定義的行為仍然存在,應該通過使用 std::atomic 或同步來避免。
在這種情況下,您可以將std::atomic<bool>
與std::memory_order_relaxed
因為您不需要任何同步或排序 wrt。 寫入或讀取線程中的其他操作。 這將為您提供原子性(無撕裂)並假設該值可以異步更改,而無需讓編譯器使用任何 asm 屏障指令來創建更多排序 wrt。 其他操作。
因此,在沒有任何同步的情況下使用原子是可能且安全的,甚至不需要像 seq_cst 或獲取/釋放加載和存儲那樣在寫入器和讀取器之間創建同步。 您可以使用此同步來安全地共享非原子變量或數組,例如,當指針為非 NULL 時讀取器讀取的atomic<int*> buffer
。
但是如果只有原子變量本身是共享的,你可以讓讀者讀取當前值,而不關心同步。 如果您不需要重新讀取短循環的每次迭代,每次函數調用只需一次,您可能希望將其讀入本地臨時文件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.