![](/img/trans.png)
[英]CPP: Is this a reasonable way to go about thread safe FIFIO message queues
[英]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
函數:
當一個線程被“正常”通知而另一個線程被虛假通知時的行為是,其中一個線程(無論哪個,以更快的速度運行)獲取鎖並確認隊列為非空,然后彈出頂部元素並釋放鎖; 在較快的線程釋放鎖之前,丟失爭用鎖的線程不會獲取鎖,因此它會看到已經清空的隊列,並確定這是一個虛假的喚醒,然后重新進入睡眠狀態。
重要的是,虛假喚醒的線程是否贏得了爭奪鎖(和排隊的項目)的競爭並不重要。 其中一個線程的行為好像正常喚醒(發現條件為真並按預期工作),一個線程的行為好像是虛假喚醒(發現條件為假並按預期返回等待狀態),並且代碼整體上表現正常。
我認為在這種情況下,通知的線程和喚醒的線程有相同的機會從隊列中彈出,這僅取決於CPU如何做出調度決定(哪個更快)。
除非您想指定哪個線程應該具有權限,否則必須更改實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.