使用QWaitCondition类解决生产者和消费者问题。
源文件“main.cpp”的具体内容如下:
#include <QCoreApplication>
#include <QWaitCondition>
#include <QMutex>
#include <QThread>
#include <stdio.h>
const int DataSize=1000;
const int BufferSize=80;
int buffer[BufferSize];
QWaitCondition bufferEmpty;
QWaitCondition bufferFull;
QMutex mutex; //使用互斥量保证对线程操作的原子性。
int numUsedBytes=0; //变量numUsedBytes表示存在多少“可用字节”。
int rIndex=0; //本例中启动了两个消费者线程,并且这两个线程读取同一个缓冲区,为了不重复读取,设置全局变量rIndex用于指示当前所读取缓冲区位置。
生产者线程Producer类继承自QThread类,其声明如下:
class Producer : public QThread
{
public:
Producer();
void run();
};
Producer()构造函数无须实现:
Producer::Producer()
{
}
Producer::run()函数的具体内容如下:
void Producer::run()
{
for(int i=0;i<DataSize;i++) // for循环中的所有语句都需要使用互斥量加以保护,以保证其操作的原子性。
{
mutex.lock();
if(numUsedBytes==BufferSize) //首先检查缓冲区是否已被填满。
bufferEmpty.wait(&mutex); //如果缓冲区已被填满,则等待“缓冲区有空位”(bufferEmpty变量)条件成立。wait()函数将互斥量解锁并在此等待。
buffer[i%BufferSize]=numUsedBytes; //如果缓冲区未被填满,则向缓冲区中写入一个整数值。
++numUsedBytes; //增加numUsedBytes变量
bufferFull.wakeAll(); //后唤醒等待“缓冲区有可用数据”(bufferEmpty变量)条件为“真”的线程。
mutex.unlock();
}
}
这里介绍一下Wait()函数:
wait()函数原型如下:
bool QWaitCondition::wait
(
QMutex * mutex,
unsigned long time = ULONG_MAX
)
① 参数mutex为一个锁定的互斥量。如果此参数的互斥量在调用时不是锁定的或者出现递归锁定的情况,则wait()函数将立刻返回。
② 参数time为等待时间。
调用wait()操作的线程使得作为参数的互斥量在调用前首先变为解锁定状态,然后自身被阻塞变为等待状态直到满足以下条件之一:
(1)其他线程调用了wakeOne()或者wakeAll()函数,这种情况下将返回“true”值。
(2)第2个参数time超时(以毫秒为单位),该参数默认情况下为ULONG_MAX,表示永不超时,这种情况下将返回“false”值。
(3)wait()函数返回前会将互斥量参数重新设置为锁定状态,从而保证从锁定状态到等待状态的原子性转换。
消费者线程Consumer类继承自QThread类,其声明如下:
class Consumer : public QThread
{
public:
Consumer();
void run();
};
Consumer()构造函数中无须实现内容:
Consumer::Consumer()
{
}
Consumer::run()函数的具体内容如下:
void Consumer::run()
{
forever
{
mutex.lock();
if(numUsedBytes==0)
bufferFull.wait(&mutex); //当缓冲区中无数据时,等待“缓冲区有可用数据”(bufferFull变量)条件成立。
printf("%ul::[%d]=%d\n",currentThreadId(),rIndex,buffer[rIndex]);// 当缓冲区中有可用数据即条件成立时,打印当前线程号和rIndex变量,以及其指示的当前可读取数据。这里为了区分究竟是哪一个消费者线程消耗了缓冲区里的数据,使用了QThread类的currentThreadId()静态函数输出当前线程的ID。这个ID在X11环境下是一个unsigned long 类型的值。
rIndex=(++rIndex)%BufferSize; //将rIndex变量循环加1
--numUsedBytes; // numUsedBytes变量减1,即可用的数据减1。
bufferEmpty.wakeAll(); //唤醒等待“缓冲区有空位”(bufferEmpty变量)条件的生产者线程。
mutex.unlock();
}
printf("\n");
}
main()函数的具体内容如下:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Producer producer;
Consumer consumerA;
Consumer consumerB;
producer.start();
consumerA.start();
consumerB.start();
producer.wait();
consumerA.wait();
consumerB.wait();
return a.exec();
}
程序最终的运行结果如下图所示: