![](/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.