C++ 在生产者消费者情况下使用条件变量

C++ 在生产者消费者情况下使用条件变量,c++,boost,multithreading,condition-variable,C++,Boost,Multithreading,Condition Variable,我试图学习条件变量,以及如何在生产者-消费者的情况下使用它。我有一个队列,其中一个线程将数字推入队列,而另一个线程从队列中弹出数字。当生产线程放置了一些数据时,我想使用条件变量向消费线程发送信号。问题是,有时(或大多数情况下),它最多只将两个项目推入队列,然后挂起。我在product()函数中指出了它在调试模式下运行时停止的位置。有人能帮我指出为什么会发生这种情况吗 我有以下全局变量: boost::mutex mutexQ; // mutex protecting

我试图学习条件变量,以及如何在生产者-消费者的情况下使用它。我有一个队列,其中一个线程将数字推入队列,而另一个线程从队列中弹出数字。当生产线程放置了一些数据时,我想使用条件变量向消费线程发送信号。问题是,有时(或大多数情况下),它最多只将两个项目推入队列,然后挂起。我在product()函数中指出了它在调试模式下运行时停止的位置。有人能帮我指出为什么会发生这种情况吗

我有以下全局变量:


boost::mutex mutexQ;               // mutex protecting the queue
boost::mutex mutexCond;            // mutex for the condition variable
boost::condition_variable condQ;
以下是我的消费者线索:


void consume()
{
    while( !bStop )   // globally declared, stops when ESC key is pressed
    {
        boost::unique_lock lock( mutexCond );
        while( !bDataReady )
        {
            condQ.wait( lock );
        }

        // Process data
        if( !messageQ.empty() )
        {
            boost::mutex::scoped_lock lock( mutexQ );

            string s = messageQ.front();   
            messageQ.pop();
        }
    }
}

void produce()
{
    int i = 0;

    while(( !bStop ) && ( i < MESSAGE ))    // MESSAGE currently set to 10
    {
        stringstream out;
        out << i;
        string s = out.str();

        boost::mutex::scoped_lock lock( mutexQ );
        messageQ.push( s );

        i++;
        {
            boost::lock_guard lock( mutexCond );  // HANGS here
            bDataReady = true;
        }
        condQ.notify_one();
    }
}
下面是我的制作人帖子:


void consume()
{
    while( !bStop )   // globally declared, stops when ESC key is pressed
    {
        boost::unique_lock lock( mutexCond );
        while( !bDataReady )
        {
            condQ.wait( lock );
        }

        // Process data
        if( !messageQ.empty() )
        {
            boost::mutex::scoped_lock lock( mutexQ );

            string s = messageQ.front();   
            messageQ.pop();
        }
    }
}

void produce()
{
    int i = 0;

    while(( !bStop ) && ( i < MESSAGE ))    // MESSAGE currently set to 10
    {
        stringstream out;
        out << i;
        string s = out.str();

        boost::mutex::scoped_lock lock( mutexQ );
        messageQ.push( s );

        i++;
        {
            boost::lock_guard lock( mutexCond );  // HANGS here
            bDataReady = true;
        }
        condQ.notify_one();
    }
}

必须使用与在条件变量中使用的相同的互斥来保护队列

这应该是您所需要的全部:

void consume()
{
    while( !bStop )
    {
        boost::scoped_lock lock( mutexQ);
        // Process data
        while( messageQ.empty() ) // while - to guard agains spurious wakeups
        {
            condQ.wait( lock );

        }
        string s = messageQ.front();            
        messageQ.pop();
    }
}

void produce()
{
    int i = 0;

    while(( !bStop ) && ( i < MESSAGE ))
    {
        stringstream out;
        out << i;
        string s = out.str();

        boost::mutex::scoped_lock lock( mutexQ );
        messageQ.push( s );
        i++;
        condQ.notify_one();
    }
}
void消费()
{
而(!bStop)
{
boost::作用域锁定(mutexQ);
//过程数据

while(messageQ.empty())//while-防止虚假唤醒 { 等待(锁定); } 字符串s=messageQ.front(); messageQ.pop(); } } 无效产品() { int i=0; 而(!bStop)和&(iout@nos:谢谢,您的解决方案成功了。这是条件变量最常见的应用程序/用法,对吗?//while-防止虚假唤醒“请您解释一下为什么需要while循环。这是否意味着等待()在某些情况下,是的,但可能不在这个小示例中。这里有一些解释,这是pthreads而不是boost,但是boost on*nixes使用pthreads,并且不能真正采取任何措施来对付它。使用while()而不是if(),更容易将代码更改为具有多个使用者,在这种情况下,如果另一个使用者在您之前获取了该值,那么您最终会做正确的事情。(如果您具有多个使用者,condQ.notify_one()可以唤醒多个使用者)@否:我知道这是一个老话题,但我有一个问题。我想你可以通过设置bStop=true来停止这个过程,但是如果consume()呢因为队列是空的,所以此时正在等待?生产者停止生产,因此消费者不再获得任何数据,而只是等待。因此,它不需要检查bStop变量。我的问题清楚吗?您将如何解决此问题?@PolyVox是的,因此您需要发送消息来唤醒它并设置bStop。这可能是错误的这可能是一条消费者认为是“停止”消息的特殊消息。FWIW,这个错误是“锁反转”的完美例子。在一个线程中,你先锁定mutexQ,然后不释放它就锁定mutexCond。在另一个线程中,你先锁定mutexCond,然后再锁定mutexQ。这几乎总是错误的。一个线程获得一个锁,另一个线程同时获得另一个锁。然后他们都会等待获得他们没有的锁。这是他们永远无法获得的。简单的解决方法是要么使用更少的锁(在这种情况下这是正确的,即使不是反转),要么定义锁的“层次结构”,这样您就可以始终按照一致的顺序使用它们。