![](/img/trans.png)
[英]What's the difference between notify_all() and notify_one() of std::condition_variable?
[英]Is there a `notify_one()` queue for `std::condition_variable`s?
考慮第一個線程 function 和全局變量:
std::mutex mut;
std::condition_variable officer;
bool firstPlayerIsReady = false;
bool secondPlayerIsReady = false;
void firstPlayer(){
constexpr auto doIt = true;
while(doIt)
{
std::unique_lock lock{mut};
auto toContinue = ring();
secondPlayerIsReady = true;
firstPlayerIsReady = false;
officer.notify_one(); //#1
if(!toContinue) return;
officer.wait(lock,[=](){ return firstPlayerIsReady;});
}
}
它調用一些 ring 並且 ring() 返回一個繼續條件; 然后它會在下一個循環中更新每個線程的就緒值;
考慮下一個線程:
void secondPlayer(){
constexpr auto doIt = true;
while(doIt)
{
auto period = std::chrono::seconds(5);
std::this_thread::sleep_for(period);
std::unique_lock lock{mut}; //#2
officer.wait(lock,[this](){ return secondPlayerIsReady;});
auto toContinue = ring();
firstPlayerIsReady = true;
secondPlayerIsReady = false;
officer.notify_one();
if(!toContinue) return;
}
}
該線程等待 5 秒后被 wait() 鎖定,直到第一個線程調用 notify_one(); 此外,類似於第一個線程。
先驗地,帶有#1 標記的行比帶有#2 標記的行執行得早,因此通知在第二個線程被鎖定之前發送。 問題是——是否有一個 notify_one ( ) 隊列? 否則,顯然不會發送通知。
沒有隊列。 如果一個線程調用notify_one
並且沒有其他線程在等待,它將不會執行任何操作。
這就是為什么在您的示例中有謂詞的原因
officer.wait(lock,[this](){ return secondPlayerIsReady;});
因此,當線程調用此方法時,如果secondPlayerIsReady
為true,則該線程將完全不等待,而僅跳過該行。
因此,只要正確設置該標志,就notify_one
太早地調用notify_one
沒問題。 只需記住,修改后該標志需要由互斥體保護。
@super 完全正確,但我真的很難理解這個概念,所以我想用我自己的話來表達並添加我自己的答案。 開始:
std::condition_variable
沒有底層通知隊列...... ...但這根本不重要,只要您使用 boolean 謂詞,消費者就不會錯過在消費者點擊wait()
function之前發送的早期通知(由生產者發出)!
這是因為此調用將 lambda function boolean 謂詞作為第二個參數:
cv.wait(lock, []() {
return sharedData.isNewData;
});
...與這個while
循環完全相同:
while (sharedData.isNewData == false) // OR: `while (!sharedData.isNewData)`
{
cv.wait(lock);
}
...和 while 循環的cv.wait(lock);
line 只有在謂詞一開始就為false
時才會被調用!
詳細:
沒有底層通知隊列,也沒有計數器,也沒有 boolean 標志。 相反,我們檢查的boolean 謂詞是標志,而且,它在wait()
function 開始時,在睡眠之前,以及在wait()
function 結束時,在睡眠之后和每次線程時都被檢查醒來。 wait()
function僅在謂詞開始為false
時才使線程休眠,並且僅在謂詞為true
時通過返回退出wait()
function。 看看上面的while
循環版本,這將變得非常清楚。
因此,如果生產者線程將共享謂詞設置為true
,然后發送my_condition_variable.notify_one()
調用,如果消費者線程尚未等待,則它不會收到該通知。 但是,這並不重要! 只要消費者線程使用 2 參數wait()
調用(第二個參數是 boolean 謂詞),或者使用while
循環謂詞檢查技術,那么一旦消費者線程命中wait()
調用(或 while 循環),謂詞將被視為true
,整個 while 塊和等待睡眠將被完全跳過,消費者將提前 go 並立即運行,就像它在等待時收到notify_one()
通知一樣,當使用謂詞時,最終結果與條件變量確實具有長度為 1 的基礎通知隊列(或標志)相同。
看:
是:template< class Predicate > void wait( std::unique_lock<std::mutex>& lock, Predicate stop_waiting );
相當於
while (;stop_waiting()) { wait(lock); }
std::condition_variable
的詳細完整示例以及如何在我的eRCaGuy_hello_world 存儲庫中的生產者-消費者線程安全隊列中使用它: std_mutex_vs_std_lock_guard_vs_std_unique_lock_vs_std_scoped_lock_README.md
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.