QT学习:线程等待与唤醒

使用QWaitCondition类解决生产者和消费者问题。
源文件“main.cpp”的具体内容如下:

#include  
#include  
#include  
#include  
#include  
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(); 
} 

程序最终的运行结果如下图所示:
QT学习:线程等待与唤醒_第1张图片

你可能感兴趣的:(QT学习,qt,多线程)