如果被虚假唤醒,消费者线程是不是会收到 condition_variable 通知信号

Posted

技术标签:

【中文标题】如果被虚假唤醒,消费者线程是不是会收到 condition_variable 通知信号【英文标题】:Will consumer thread receive condition_variable notify signal if spuriously woken up如果被虚假唤醒,消费者线程是否会收到 condition_variable 通知信号 【发布时间】:2017-05-13 14:40:01 【问题描述】:

我们知道条件变量容易被虚假唤醒。假设我们有一个与互斥锁和条件变量同步的 1-producer-1-consumer 队列。消费者线程被虚假唤醒。 问题是——消费者线程会错过来自生产者的通知信号吗? 我知道这是极不可能的.. 但是通过这种实现是否仍然有可能丢失队列中的最后一个元素?

【问题讨论】:

"消费者线程会错过生产者的通知信号吗?" 为什么会这样呢?这就是为什么有一个与 cv 一起使用的互斥锁。你能告诉minimal reproducible example你有什么吗? afaik 条件变量的重点是处理虚假唤醒的情况 【参考方案1】:

如果调用wait() 的代码编写不正确,它确实可能会错过唤醒。但这有点反常。通常的成语是:

lock the mutex
while the condition is not satisfied
    wait on the condition variable

信号线程应该在发出信号之前锁定互斥体:

lock the mutex
signal the condition variable

等待条件变量会在等待期间解锁互斥锁。但是,当等待调用返回时,互斥锁将被锁定。因此,在虚假唤醒时,等待线程将持有互斥锁,直到它恢复等待。当等待线程持有互斥锁时,发信号线程不能发信号给条件变量。当等待线程实际等待时,互斥锁被解锁,信号线程可以继续发出信号;等待线程会得到信号,一旦信号线程释放互斥体,等待线程将恢复执行。

所以,不,正确的代码不会错过任何信号。但是如果等待线程释放互斥体并在检查其条件的过程中重新获取它,则信号可能在等待线程调用等待之前发生,并且信号将丢失。不要那样做。

【讨论】:

"当等待线程持有互斥锁时,信号线程不能向条件变量发出信号。" - 这就是我所缺少的。谢谢!【参考方案2】:

虚假唤醒意味着它可能会虚假唤醒,然后必须继续等待。

这根本不是指错过事件的可能性,因为如果这是真的,那将毫无用处。

这个链接提供了关于cv和wait方法的详细解释:

https://www.codeproject.com/Articles/598695/Cplusplus-threads-locks-and-condition-variables

 // print a starting message
    
        std::unique_lock<std::mutex> locker(g_lockprint);
        std::cout << "[logger]\trunning..." << std::endl;
    

    // loop until end is signaled
    while(!g_done)
    
        std::unique_lock<std::mutex> locker(g_lockqueue);

        g_queuecheck.wait(locker, [&]()return !g_codes.empty(););

        // if there are error codes in the queue process them
        while(!g_codes.empty())
        
            std::unique_lock<std::mutex> locker(g_lockprint);
            std::cout << "[logger]\tprocessing error:  " << g_codes.front() << std::endl;
            g_codes.pop();
        
    

【讨论】:

以上是关于如果被虚假唤醒,消费者线程是不是会收到 condition_variable 通知信号的主要内容,如果未能解决你的问题,请参考以下文章

生产者消费者和虚假唤醒

多线程下虚假唤醒问题

虚假唤醒

JAVA线程虚假唤醒

线程间通信 生产者消费者虚假唤醒

java多线程 生产者消费者案例-虚假唤醒