簡體   English   中英

線程安全隊列和虛假喚醒

[英]Thread safe queues and spurious wakes

我目前正在閱讀有關C ++中多線程的書。 在第一章中,我找到了線程安全隊列的一些源代碼。 它大致是這樣構建的:

template<typename T>
class QueueThreadSafe
{
private:
    std::mutex m_mutex;
    std::queue<T> m_dataQueue;
    std::condition_variable m_dataCondition;

public:
    void push(T someValue)
    {
        std::lock_guard<std::mutex> guard(m_mutex);
        m_dataQueue.push(someValue);
        m_dataCondition.notify_one();
    }

    void pop(T &retVal)
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_dataCondition.wait(lock, [this]{return !m_dataQueue.empty();});
        retVal = m_dataQueue.front();
        m_dataQueue.pop();
    }
};

當將值推入隊列時,將通知數據條件,並且彈出中的某些(可能)等待線程可以恢復工作。 使我感到困惑的是這種情況下的虛假喚醒。 如果在同一時間通知一個線程,而另一個線程在同一時間喚醒,該怎么辦? 當然,他也看到一個不空的隊列。 在這種情況下,兩個不同的線程將嘗試彈出一個值,其中可能僅存在一個值-經典競爭條件。

我在這里想念什么嗎? 有一個更好的方法嗎?

虛假喚醒僅意味着您需要在喚醒時檢查喚醒條件是否仍然有效。 由於傳遞了wait函數:

  1. 用於互斥的鎖,以及
  2. 判斷是否滿足等待條件的謂詞

當一個線程被“正常”通知而另一個線程被虛假通知時的行為是,其中一個線程(無論哪個,以更快的速度運行)獲取鎖並確認隊列為非空,然后彈出頂部元素並釋放鎖; 在較快的線程釋放鎖之前,丟失爭用鎖的線程不會獲取鎖,因此它會看到已經清空的隊列,並確定這是一個虛假的喚醒,然后重新進入睡眠狀態。

重要的是,虛假喚醒的線程是否贏得了爭奪鎖(和排隊的項目)的競爭並不重要。 其中一個線程的行為好像正常喚醒(發現條件為真並按預期工作),一個線程的行為好像是虛假喚醒(發現條件為假並按預期返回等待狀態),並且代碼整體上表現正常。

我認為在這種情況下,通知的線程和喚醒的線程有相同的機會從隊列中彈出,這僅取決於CPU如何做出調度決定(哪個更快)。

除非您想指定哪個線程應該具有權限,否則必須更改實現。

暫無
暫無

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

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