簡體   English   中英

std::condition_variable 內存寫入可見性

[英]std::condition_variable memory writes visibility

std::condition_variable::notify_one()std::condition_variable::notify_all()保證在調用之前當前線程中的非原子內存寫入在通知線程中可見?

其他線程做:

{
    std::unique_lock lock(mutex);
    cv.wait(lock, []() { return values[threadIndex] != 0; });
    // May a thread here see a zero value and therefore start to wait again?
}

主線程執行:

fillData(values); // All values are zero and all threads wait() before calling this.
cv.notify_all(); // Do need some memory fence or lock before this
                 // to ensure that new non-zero values will be visible
                 // in other threads immediately after waking up?

notify_all() 不存儲一些原子值從而強制執行內存排序嗎? 我沒有澄清。

UPD :根據 Superlokkus 的回答和這里的回答:我們必須獲取一個鎖以確保其他線程中的內存寫入可見性(內存傳播),否則在我的情況下線程可能會讀取零值。

我也錯過了這里關於 condition_variable 的引用,它專門回答了我的問題。 在修改必須立即可見的情況下,甚至必須在鎖下修改原子變量。

即使共享變量是原子的,也必須在互斥鎖下進行修改,才能將修改正確發布到等待線程。

我猜您正在混淆所謂的原子值的內存排序和基於鎖的經典同步機制。

當你有一個在線程之間共享的數據時,比如說一個int ,一個線程不能簡單地讀取它,而另一個線程可能同時寫入它。 否則我們就會有數據競賽。

為了長時間解決這個問題,我們使用了經典的基於鎖的同步:線程至少共享一個互斥鎖和int 要讀取或寫入任何線程必須先持有鎖,這意味着它們在互斥鎖上等待。 互斥體被構建,以便它們可以同時發生。 如果一個線程贏得互斥鎖,它可以更改或讀取int然后應該解鎖它,這樣其他人也可以讀/寫。 使用像您使用的條件變量只是為了使“讀取器等待寫入器更改值”的模式更有效,它們會被 cv 喚醒,而不是定期等待鎖定、讀取和解鎖,這會被稱為忙等待。

因此,因為在等待互斥鎖之后或在您的情況下,正確地(仍然需要互斥鎖)等待條件變量后,您將鎖定保持在任何位置,您可以更改int 讀者將在作者能夠寫出新值后讀取新值,而不是舊值。 更新:但是,如果必須添加一件事,這也可能是混淆的原因:條件變量受所謂的虛假喚醒的影響。 這意味着即使您寫入沒有通知任何線程,讀取線程可能仍會喚醒,互斥鎖被鎖定。 因此,您必須檢查您的作者是否真的喚醒了您,這通常是由作者通過更改另一個數據來通知這一點來完成的,或者通過使用您已經想共享的相同數據是否合適。 std::condition_variable::wait的 lambda 參數重載只是為了使檢查和返回睡眠代碼看起來更漂亮一些。 根據你現在的問題,我不知道你是否想在這份工作中使用你的values

但是,“主”線程的代碼片段不正確或不完整:您沒有在互斥鎖上進行同步以更改values 您必須為此持有鎖,但可以在沒有鎖的情況下進行通知。

std::unique_lock lock(mutex);
fillData(values); 
lock.unlock();
cv.notify_all(); 

但是這些基於互斥鎖的模式有一些缺點並且速度很慢,一次只有一個線程可以做某事。 這就是所謂的原子,就像std::atomic<int>發揮作用。 它們可以同時被多個線程同時寫入和讀取,而無需互斥鎖。 內存排序只是一個需要考慮的事情,並且對於您以有意義的方式使用其中幾個或者您不需要“寫入后,我永遠不會看到舊值”保證的情況進行優化。 但是,使用它的默認內存排序memory_order_seq_cst您也可以。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM