簡體   English   中英

std::condition_variable wait() 和 notify_one() 同步

[英]std::condition_variable wait() and notify_one() synchronization

前言:我在這里看到過類似的問題,但似乎沒有一個能回答我的問題。

有沒有一種可靠的方法來確保在從生產者線程第一次調用notify_one()之前調用消費者線程中的wait()方法?

即使在消費者線程中使用unique_lock ,也有可能生產者線程首先運行,鎖定互斥鎖並在消費者調用wait()之前調用notify() wait() ,因此,我的應用程序將丟失第一個notify()調用。

編輯:感謝您的所有回答,他們確實幫助了我。 我的問題是在這個消費者循環中的第一個 wait-notify() :

while (!timeToQuit) {
    gdcv.wait(gdcondlock);
    gdlock.lock();
    //spurious wakeup
    if (gdQueue.empty()) {
      gdlock.unlock();
      continue;
    }
    //some work here
    gdlock.unlock();
} 

我想我必須為第一次循環迭代編寫額外的代碼。

EDIT2:這個循環和第二個鎖(unique_lock btw)在那里,因為有多個生產者和消費者訪問隊列。

EDIT3:在boost::lockfree::queue幫助下等待此特定線程的正確方法,以防有人遇到類似問題:

  nfq_data* data;
  while (!timeToQuit) {
    gdcv.wait(gdlock,[&]{return !gdQueue.empty() || timeToQuit;});
    gdQueue.pop(data);
    gdlock.unlock();
  }

即使在消費者線程中使用 unique_lock ,也有可能生產者線程將首先運行,鎖定互斥鎖並在消費者調用 wait() 之前調用 noify(),因此,我的應用程序將丟失第一個 nofity() 調用。

要么消費者有什么需要等待的,要么沒有。 如果它有什么要等待的,那就沒有問題。 如果它沒有什么可等待的,請不要調用wait 真的就是這么簡單。

呼叫wait ,當且僅當,你要等待。

條件變量的存在是為了解決如何釋放鎖並等待而不冒等待已經發生的事情的風險的問題。 他們通過提供一個原子地釋放鎖並等待的函數來解決它。 他們不能錯過喚醒,因為他們在決定睡覺時持有鎖。

不,由您來處理線程同步。

如果你不想錯過通知調用,即使它發生在消費者開始等待之前,你必須控制這種可能性,記錄生產者完成的某處,然后根本不調用wait()函數。

例如,您可以實現一種事件類,僅當事件尚未發生時才等待條件變量:

#include <mutex>
#include <condition_variable>

class Event
{
public:
    Event();
    void set_event();
    void reset_event();
    void wait_event();
private:
    std::mutex mtx;
    std::condition_variable cv;
    bool is_set;
};

Event::Event()
: is_set{false}
{}

void Event::set_event()
{
    std::lock_guard<std::mutex> lck{mtx};
    is_set = true;
    cv.notify_all();
}

void Event::reset_event()
{
    std::lock_guard<std::mutex> lck{mtx};
    is_set = false;
}

void Event::wait_event()
{
    std::unique_lock<std::mutex> lck{mtx};
    if( is_set )
        return;

    cv.wait(lck, [this]{ return is_set;} );
}

聽起來您正試圖(錯誤地)使用condition_variable來實現“障礙”。

條件變量允許您等待某個條件變為真,通過某個謂詞進行測試,例如“有可用的工作”,並且您應該始終在等待之前測試謂詞,以確保您不會“錯過”事件並等待你應該在什么時候工作。

僅使用條件變量等待,而沒有關聯的謂詞,效果不佳。 這不是它們的設計用途。

如果您試圖讓所有線程在代碼中的特定點等待,並且僅在它們全部到達時才繼續,那么您使用的概念略有不同,稱為屏障。

C++ 並發 TS 為 C++ 標准庫定義了障礙(以及稍微簡單的“閂鎖”概念),請參閱草案N4538

您可以通過定義一個帶有計數器的類來自己定義屏障,該類在內部使用條件變量。 它需要等待的條件是“所有 N 個線程都增加了計數器”。 然后你可以讓生產者和所有消費者在屏障處等待,他們都會阻塞,直到最后一個線程到達屏障。 即使生產者到達屏障並首先開始等待,您也可以保證消費者也會在屏障處停止等待,直到所有線程到達它,然后它們都會繼續進行。

即使在消費者線程中使用 unique_lock 也有可能生產者線程將首先運行,鎖定互斥鎖並在消費者調用 wait() 之前調用 noify(),因此,我的應用程序將丟失第一個 nofity() 調用

如果生產者已經運行,那么消費者不必等待,因此不應調用wait 如果消費者只在需要的時候等待——並且條件是同步的——那么它不會錯過它需要注意的通知。

暫無
暫無

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

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