簡體   English   中英

是否有用於 std::condition_variable 的 notify_one() 隊列?

[英]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 的基礎通知隊列(或標志)相同。

看:

  1. https://en.cppreference.com/w/cpp/thread/condition_variable/wait - 它指出這個模板化的 function:
     template< class Predicate > void wait( std::unique_lock<std::mutex>& lock, Predicate stop_waiting );
    是:

    相當於

    while (;stop_waiting()) { wait(lock); }
  2. @super的回答,他讓我走上了正確的軌道,讓我自己終於明白了這一點

也可以看看

  1. 我記錄了上述信息,以及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.

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