QWaitCondition介绍
QWaitCondition 是一个 Qt 框架提供的等待条件类,用于多个线程之间的同步。通常和互斥锁(QMutex)或读写锁(QReadWriteLock)一起使用。
QWaitCondition 可以让线程在某个条件成立时等待,直到其他线程发出信号后唤醒它们。例如,在一个生产者消费者模型中,当队列已满时,生产线程需要等待;当队列为空时,消费线程也需要等待。
与 QMutex 或 QReadWriteLock 不同,QWaitCondition 并不会完成实际的锁定操作,而是提供了 wait() 方法来保持当前线程的休眠状态,并重新将线程加入线程调度器中。当其他线程改变了条件以后,通过 wakeOne() 或 wakeAll() 信号激活等待线程。
QWaitCondition主要特点在于其针对条件变量(condition variable)做优化,这使得性能更高,且适合跨平台应用。在使用上,QWaitCondition 主要配合互斥锁使用,互斥锁用于保证条件判断的原子性,等待的线程在进入等待前会释放锁,从而避免了死锁的问题。
代码示例
#ifndef DATAMANAGER_H
#define DATAMANAGER_H
#include <QDebug>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
class Data {
public:
Data() : m_num(0), m_max(100) {}
void produce(){
QMutexLocker locker(&m_mutex);
while(m_num > m_max){
qDebug() << "Queue is full, wait for consumer to take products";
m_notFull.wait(&m_mutex);
}
m_num++;
qDebug() << "Produce a product, num = " << m_num;
if(m_num > 0){
m_notEmpty.wakeOne();
}
}
void consume(){
QMutexLocker locker(&m_mutex);
while(m_num <= 0){
qDebug() << "Queue is empty, wait for producer to produce products";
m_notEmpty.wait(&m_mutex);
}
m_num--;
qDebug() << "Consume a product, num = " << m_num;
if(m_num < m_max){
m_notFull.wakeOne();
}
}
private:
QMutex m_mutex;
QWaitCondition m_notEmpty;
QWaitCondition m_notFull;
int m_num;
int m_max;
};
#endif // DATAMANAGER_H
在上述代码中,我们定义了一个 Data 类,该类表示一个共享的数据队列。在 produce() 和 consume() 方法中,我们使用了 wait()、wakeOne() 激活和唤醒所有等待的线程,通过 QMutex 来保证互斥锁在判断 num 的值时不会被其他线程修改,从而确保了多线程安全。
#ifndef THREADMANAGER_H
#define THREADMANAGER_H
#include <QDebug>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include "datamanager.h"
class Producer : public QThread {
Q_OBJECT
public:
Producer(Data *data): m_data(data){}
void run() override {
while(true)
{
m_data->produce();
msleep(500);
}
}
private:
Data *m_data;
};
class Consumer : public QThread {
Q_OBJECT
public:
Consumer(Data *data): m_data(data){}
void run() override {
while(true)
{
m_data->consume();
msleep(1000);
}
}
private:
Data *m_data;
};
#endif // THREADMANAGER_H
#include <QCoreApplication>
#include "datamanager.h"
#include "threadmanager.h"
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
Data data;
Producer producer(&data);
Consumer consumer(&data);
producer.start();
consumer.start();
producer.wait();
consumer.wait();
return app.exec();
}
我们创建了 Producer 对象和 Consumer 对象,用于循环执行 produce() 和 consume() 方法,并启动这两个对象的线程来模拟生产者和消费者在不同的线程中同时运行的情况。
由于生产的速度比消费的速度快,程序的输出最终会稳定在如下的状态。可以通过调整生产和消费的时间,改变输出结果。