简体   繁体   English

是否有用于 std::condition_variable 的 notify_one() 队列?

[英]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:开始:

No, 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:看:

  1. https://en.cppreference.com/w/cpp/thread/condition_variable/wait - it states that this templated function: https://en.cppreference.com/w/cpp/thread/condition_variable/wait - 它指出这个模板化的 function:
     template< class Predicate > void wait( std::unique_lock<std::mutex>& lock, Predicate stop_waiting );
    is:是:

    Equivalent to相当于

    while (;stop_waiting()) { wait(lock); }
  2. Answer by @super , who set me on the right track to finally understand this myself @super的回答,他让我走上了正确的轨道,让我自己终于明白了这一点

See also也可以看看

  1. I documented the above information, with detailed full examples of 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.md我记录了上述信息,以及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.

相关问题 std :: condition_variable的notify_all()和notify_one()有什么区别? - What's the difference between notify_all() and notify_one() of std::condition_variable? std :: condition_variable :: notify_one可重入吗? - Is std::condition_variable::notify_one reentrant? std::condition_variable wait() 和 notify_one() 同步 - std::condition_variable wait() and notify_one() synchronization 为什么 std::condition_variable::notify_one 阻塞? - why is std::condition_variable::notify_one blocking? 如果有很多线程在等待通知,std::condition_variable::notify_one() function 通知哪一个? - If there are many threads are waiting to be notify, which one does the std::condition_variable::notify_one() function notify? 为什么在 std::condition_variable 中,notify_all 比 notify_one 工作得更快(在随机请求上)? - Why in std::condition_variable notify_all works faster than notify_one (on random requests)? 我是否需要同步std :: condition_variable / condition_variable_any :: notify_one - Do I need to synchronize std::condition_variable/condition_variable_any::notify_one 在调用 std::condition_variable::wait() 之前多次调用 std::condition_variable::notify_one() - Calling std::condition_variable::notify_one() multiple times before std::condition_variable::wait() is called std::condition_variable::notify_one: 如果有些线程有错误的谓词,它会唤醒多个线程吗? - std::condition_variable::notify_one: does it wake multiple threads if some have false predicate? std :: condition_variable :: notify_one()多次调用而无需上下文切换 - std::condition_variable::notify_one() called several times without context switching
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM