[英]Is there a `notify_one()` queue for `std::condition_variable`s?
Consider the first thread function and global variables:考虑第一个线程 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;});
}
}
It calls some ring and ring() returns a continuation condition;它调用一些 ring 并且 ring() 返回一个继续条件; It then updates readiness values for each thread in the next loop;
然后它会在下一个循环中更新每个线程的就绪值;
Consider the next thread:考虑下一个线程:
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;
}
}
This thread wait for 5 seconds and after are locked with wait( ) until the first thread calls the notify_one( );该线程等待 5 秒后被 wait() 锁定,直到第一个线程调用 notify_one(); Further, similar to the first thread.
此外,类似于第一个线程。
A priori, the line with #1 tag was executed earlier than the line with #2 tag, therefore the notification was sent earlier than the second thread was locked.先验地,带有#1 标记的行比带有#2 标记的行执行得早,因此通知在第二个线程被锁定之前发送。 The question is - Is there a notify_one ( ) queue?
问题是——是否有一个 notify_one ( ) 队列? Otherwise, the notification wasn't sent, obviously.
否则,显然不会发送通知。
There is no queue. 没有队列。 If one thread calls
notify_one
and there are no other threads waiting it will not do anything. 如果一个线程调用
notify_one
并且没有其他线程在等待,它将不会执行任何操作。
That's why you have the predicate, in your example 这就是为什么在您的示例中有谓词的原因
officer.wait(lock,[this](){ return secondPlayerIsReady;});
So when a thread calls this, if secondPlayerIsReady
is true, then the thread will not wait at all, but just skip past this line. 因此,当线程调用此方法时,如果
secondPlayerIsReady
为true,则该线程将完全不等待,而仅跳过该行。
So calling notify_one
too "early" is not a problem as long as the flag is set properly. 因此,只要正确设置该标志,就
notify_one
太早地调用notify_one
没问题。 Just remember that the flag needs to be protected by the mutex when modified. 只需记住,修改后该标志需要由互斥体保护。
@super is exactly right , but I was having a really hard time understanding this concept, so I wanted to put it into my own words and add my own answer as well. @super 完全正确,但我真的很难理解这个概念,所以我想用我自己的话来表达并添加我自己的答案。 Here goes:
开始:
std::condition_variable
s do not have an underlying notification queue...std::condition_variable
没有底层通知队列...... ...but that doesn't really matter at all, So long as you use a boolean predicate, an early notification (by a producer) which is sent before the consumer hits the wait()
function will not be missed by the consumer! ...但这根本不重要,只要您使用 boolean 谓词,消费者就不会错过在消费者点击
wait()
function之前发送的早期通知(由生产者发出)!
That is because this call with the lambda function boolean predicate as the 2nd parameter:这是因为此调用将 lambda function boolean 谓词作为第二个参数:
cv.wait(lock, []() {
return sharedData.isNewData;
});
...is exactly identical to this while
loop: ...与这个
while
循环完全相同:
while (sharedData.isNewData == false) // OR: `while (!sharedData.isNewData)`
{
cv.wait(lock);
}
...and the while loop's cv.wait(lock);
...和 while 循环的
cv.wait(lock);
line is only called if the predicate is false
in the first place! line 只有在谓词一开始就为
false
时才会被调用!
In detail:详细:
There is NOT an underlying notification queue, nor counter, nor boolean flag.没有底层通知队列,也没有计数器,也没有 boolean 标志。 Rather, the boolean predicate we check is the flag, And, it is checked both at the start of the
wait()
function, before sleeping, as well as at the end of the wait()
function, after sleeping and each time the thread wakes up.相反,我们检查的boolean 谓词是标志,而且,它在
wait()
function 开始时,在睡眠之前,以及在wait()
function 结束时,在睡眠之后和每次线程时都被检查醒来。 The wait()
function only sleeps the thread if the predicate starts out false
, and it only exits the wait()
function by returning from it when the predicate is true
. wait()
function仅在谓词开始为false
时才使线程休眠,并且仅在谓词为true
时通过返回退出wait()
function。 Look at that while
loop version just above and this will become perfectly clear.看看上面的
while
循环版本,这将变得非常清楚。
So, if the producer thread sets a shared predicate to true
, and then sends a my_condition_variable.notify_one()
call, if the consumer thread is not already waiting, it does not receive that notification.因此,如果生产者线程将共享谓词设置为
true
,然后发送my_condition_variable.notify_one()
调用,如果消费者线程尚未等待,则它不会收到该通知。 BUT, it doesn't really matter!但是,这并不重要! So long as the consumer thread is either using the 2-parameter
wait()
call (with the 2nd parameter being a boolean predicate), OR using the while
loop predicate-checking technique, then once the consumer thread hits the wait()
call (or while loop), the predicate will be seen as being true
, and the whole while block and waiting sleep will be skipped entirely, and the consumer will go ahead and run instantly as though it had received the notify_one()
notification while waiting, When the predicate is used, the end result is the same as though the condition variable did have an underlying notification queue (or flag) of length one.只要消费者线程使用 2 参数
wait()
调用(第二个参数是 boolean 谓词),或者使用while
循环谓词检查技术,那么一旦消费者线程命中wait()
调用(或 while 循环),谓词将被视为true
,整个 while 块和等待睡眠将被完全跳过,消费者将提前 go 并立即运行,就像它在等待时收到notify_one()
通知一样,当使用谓词时,最终结果与条件变量确实具有长度为 1 的基础通知队列(或标志)相同。
See:看:
is:template< class Predicate > void wait( std::unique_lock<std::mutex>& lock, Predicate stop_waiting );
Equivalent to
相当于
while (;stop_waiting()) { wait(lock); }
std::condition_variable
and how to use it in a producer-consumer thread-safe queue in my eRCaGuy_hello_world repo here: std_mutex_vs_std_lock_guard_vs_std_unique_lock_vs_std_scoped_lock_README.mdstd::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.