C++ 在生产者消费者情况下使用条件变量
我试图学习条件变量,以及如何在生产者-消费者的情况下使用它。我有一个队列,其中一个线程将数字推入队列,而另一个线程从队列中弹出数字。当生产线程放置了一些数据时,我想使用条件变量向消费线程发送信号。问题是,有时(或大多数情况下),它最多只将两个项目推入队列,然后挂起。我在product()函数中指出了它在调试模式下运行时停止的位置。有人能帮我指出为什么会发生这种情况吗 我有以下全局变量:C++ 在生产者消费者情况下使用条件变量,c++,boost,multithreading,condition-variable,C++,Boost,Multithreading,Condition Variable,我试图学习条件变量,以及如何在生产者-消费者的情况下使用它。我有一个队列,其中一个线程将数字推入队列,而另一个线程从队列中弹出数字。当生产线程放置了一些数据时,我想使用条件变量向消费线程发送信号。问题是,有时(或大多数情况下),它最多只将两个项目推入队列,然后挂起。我在product()函数中指出了它在调试模式下运行时停止的位置。有人能帮我指出为什么会发生这种情况吗 我有以下全局变量: boost::mutex mutexQ; // mutex protecting
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)和&(i out@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。这几乎总是错误的。一个线程获得一个锁,另一个线程同时获得另一个锁。然后他们都会等待获得他们没有的锁。这是他们永远无法获得的。简单的解决方法是要么使用更少的锁(在这种情况下这是正确的,即使不是反转),要么定义锁的“层次结构”,这样您就可以始终按照一致的顺序使用它们。