工作过程中,可能会使用生产者消费者模型来处理各种应用场景,而生产者消费者模型指的是生产者只负责生产数据,而消费者只负责消费数据。例如网络通信的过程中,采用生产者来接收网络数据,而消费者负责处理网络数据,这样既能各司其职,又提高了网络的通信速度。下面通过使用常见的生产者消费者模型来说明一下条件变量的使用方法。
新建一个Qt控制台程序,再新建两个线程类Producer和Consumer,这两个类继承自QThread类。
先在main.cpp中声明要用到的全局变量。代码如下。
#include <QCoreApplication>
#include <QWaitCondition>
#include <QMutex>
#include <QQueue>
QQueue<int> buffer;
QMutex mutex;
QWaitCondition fullCond;// 缓冲区变满(有数据)
QWaitCondition emptyCond;// 缓冲区变空
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
return a.exec();
}
其中,buffer是缓冲区,mutex是保护缓存区的互斥量,条件变量fullCond用来等待缓冲区变满(有数据),条件变量emptyCond用来等待缓冲区变空。
下面来实现生产者和消费者线程。生产者线程代码如下。
void Producer::run()
{
while(true)
{
mutex.lock();
while(buffer.size() >= 10)//缓冲区变满
{
emptyCond.wait(&mutex);//等待缓冲区变空
}
int num = rand();//产生一个随机数
buffer.enqueue(num);// 在队列尾部添加一个元素
qDebug() << "enqueue: " << num;
mutex.unlock();
fullCond.wakeAll();//唤醒其他等待线程
}
}
此处,假定缓冲区最多存储10个元素。先判断缓冲区是否已满,如果已满,则等待其变为空;否则,产生一个随机数放入队列中,最后通知消费者线程可以进行消费。
消费者线程代码如下。
void Consumer::run()
{
while(true)
{
mutex.lock();
while(buffer.size() <= 0)
{
fullCond.wait(&mutex);//没有数据,等待缓存区有数据
}
//如果有数据,则从队首取出一个元素
qDebug() << "dequeue: " << buffer.dequeue();
mutex.unlock();
emptyCond.wakeAll();//唤醒其他等待线程
}
}
对于消费者来说,他要先判断缓冲区是否有数据可消费。如果没有,则等待生产者生产出新的数据;如果有,则消费数据。最后,通知生产者继续生产。