3

在使用 Boost 线程的单个生产者/单个消费者应用程序中,如果生产者线程cond_var.notify_one()在消费者线程调用之前多次调用会发生cond_var.wait(lock)什么?

是否会堆叠额外的调用notify_one,以便每个调用.wait()将与调用 1:1 对应.notify_one()

编辑实现并发队列的常用示例具有以下方法:

void push(Data const& data)
{
    boost::mutex::scoped_lock lock(the_mutex);
    the_queue.push(data);
    lock.unlock();
    the_condition_variable.notify_one();
}

void wait_and_pop(Data& popped_value)
{
    boost::mutex::scoped_lock lock(the_mutex);
    while(the_queue.empty())
    {
        the_condition_variable.wait(lock);
    }

    popped_value=the_queue.front();
    the_queue.pop();
}

我使用了一些非常相似的代码,并且经历了一些奇怪的内存增长,这似乎是由于消费者线程没有每次都醒来.notify_one()(因为它仍在忙于做其他工作),并且想知道是否缺少“堆叠”可能是原因。

如果(有时)消费者线程无法跟上生产者线程,那么如果不堆叠此代码似乎会失败。如果我的理论是正确的,我将不胜感激有关如何修复此代码的建议。

4

2 回答 2

7

规格notify_one为:

C++11 30.5.1/7:效果:如果任何线程被阻塞等待*this,解除阻塞其中一个线程。

所以答案是否定的:调用notify_one并且notify_all只会唤醒当前等待的线程,并且以后不会被记住。

更新:对不起,我将问题误读为std::condition_variable. 毫不奇怪,Boost规范或多或少是相同的:

如果任何线程当前在调用or时被阻塞等待,则取消阻塞其中一个线程。*thiswaittimed_wait

关于您的编辑:如果有人调用时没有线程等待push,那么下一个要调用的线程pop根本不会等待,因为the_queue不会为空。所以条件变量不需要记住它不应该等待;该信息存储在被管理的状态中,而不是条件变量中。如果消费者跟不上生产者,那么要么加快消费,要么放慢生产;对于信号机制,您无能为力。

于 2013-01-29T12:15:14.733 回答
3

简而言之:不,它不堆叠。

notify_one()仅当另一个线程正在等待cond_var. 因此,如果您的消费者正在等待,则第一个notify_one()已解除对消费者的阻止。第二个notify_one()没有效果,因为没有线程在等待condition_variable

于 2013-01-29T12:15:24.527 回答