一、QWaitCondition简介
QWaitCondition是Qt中的一个同步原语,它是一个条件变量(condition variable)对象,允许线程等待某些条件变为满足后再继续执行。在多线程编程中,条件变量经常与锁(mutex)配合使用,通常是用于实现生产者-消费者模式,读者-写者模式等。QWaitCondition类可以用来实现上述模式,而不需要线程轮询或者繁琐的信号机制。
QWaitCondition类通常与QMutex类一起使用,QMutex用于保护共享资源的临界区,QWaitCondition用于同步线程。QWaitCondition由两个方法来实现条件等待:
- wait(QMutex *mutex, ulong time = ULONG_MAX) — 等待条件变量,释放mutex锁。
- wakeOne() — 唤醒等待条件变量的一个线程。
- wakeAll() — 唤醒等待条件变量的所有线程。
二、QWaitCondition的使用
1. 简单使用
下面的例子展示了两个线程来访问共享变量,QWaitCondition用于同步这两个线程。在示例中,首先创建一个Waiter类来等待条件变量,然后创建一个Notifier类来发出条件变量信号。
Waiter.h
“`cpp
#ifndef WAITER_H
#define WAITER_H
#include
#include
#include
class Waiter : public QThread
{
Q_OBJECT
public:
Waiter(QMutex* mutex, QWaitCondition* cond) :
m_mutex(mutex), m_cond(cond)
{}
void run() override
{
qDebug() <lock();
m_cond->wait(m_mutex);
qDebug() <unlock();
}
private:
QMutex* m_mutex;
QWaitCondition* m_cond;
};
#endif // WAITER_H
“`
Notifier.h
“`cpp
#ifndef NOTIFIER_H
#define NOTIFIER_H
#include
#include
#include
class Notifier : public QThread
{
Q_OBJECT
public:
Notifier(QMutex* mutex, QWaitCondition* cond) :
m_mutex(mutex), m_cond(cond)
{}
void run() override
{
m_mutex->lock();
QThread::sleep(1);
qDebug() <wakeOne(); // 唤醒所有waiter等待线程
m_mutex->unlock();
}
private:
QMutex* m_mutex;
QWaitCondition* m_cond;
};
#endif // NOTIFIER_H
“`
main函数
“`cpp
#include
#include
#include “Waiter.h”
#include “Notifier.h”
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMutex mutex;
QWaitCondition cond;
Waiter *waiter1 = new Waiter(&mutex, &cond);
Waiter *waiter2 = new Waiter(&mutex, &cond);
Notifier *notifier = new Notifier(&mutex, &cond);
waiter1->start();
waiter2->start();
notifier->start();
waiter1->wait();
waiter2->wait();
notifier->wait();
delete waiter1;
delete waiter2;
delete notifier;
return a.exec();
}
“`
在这个例子中,我们首先创建了一个Mutex和WaitCondition,然后创建了两个Waiter线程和一个Notifier线程。两个Waiter线程都在等待条件变量,等待Notifier线程发出条件变量信号后才会继续执行。Notifier线程可以通过调用wakeOne(或wakeAll)方法来唤醒等待线程。在释放锁之前,wait()会一直等待。
2. 复杂使用
这里使用一个模拟生产者和消费者的例子。主线程是消费者,生产者线程异步地生产数据,并在队列 ready 中放入数据,消费者线程在队列 ready 中取出数据并处理。
producer.h
“`cpp
#ifndef PRODUCER_H
#define PRODUCER_H
#include
#include
#include
#include
#include
#include
class Producer : public QThread
{
Q_OBJECT
public:
explicit Producer(QMutex *mutex, QWaitCondition *cond, QObject *parent = nullptr): QThread (parent),
m_mutex(mutex), m_condition(cond), m_ready(nullptr), m_running(false)
{}
void run() override
{
QMutexLocker locker(m_mutex);
m_running = true;
while(m_running)
{
if(m_ready && m_ready->count() enqueue(value);
qDebug() << "producer enqueue" <wakeAll();
}
}
void stop(void) {m_running = false;}
void setReady(QQueue *ready) {m_ready = ready;}
private:
void lock_wait(int ms)
{
m_mutex->unlock();
QThread::msleep(ms);
m_mutex->lock();
}
private:
QMutex *m_mutex;
QWaitCondition *m_condition;
QQueue *m_ready;
bool m_running;
};
#endif // PRODUCER_H
“`
consumer.h
“`cpp
#ifndef CONSUMER_H
#define CONSUMER_H
#include
#include
#include
#include
#include
#include
class Consumer : public QThread
{
Q_OBJECT
public:
explicit Consumer(QMutex *mutex, QWaitCondition *cond, QObject *parent = nullptr): QThread (parent),
m_mutex(mutex), m_condition(cond), m_ready(nullptr), m_running(false)
{}
void run() override
{
QMutexLocker locker(m_mutex);
m_running = true;
while(m_running)
{
while(m_ready && m_ready->count() == 0)
{
m_condition->wait(m_mutex);
}
int value = 0;
while (m_ready && m_ready->count() > 0) {
value = m_ready->dequeue();
qDebug() << "consumer dequeue" << value;
}
// 模拟消费者消费的时间
lock_wait(100);
}
}
void setReady(QQueue *ready) {m_ready = ready;}
void stop(void) {m_running = false;}
private:
void lock_wait(int ms)
{
m_mutex->unlock();
QThread::msleep(ms);
m_mutex->lock();
}
private:
QMutex *m_mutex;
QWaitCondition *m_condition;
QQueue *m_ready;
bool m_running;
};
#endif // CONSUMER_H
“`
main函数
“`cpp
#include
#include
#include “producer.h”
#include “consumer.h”
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMutex mutex;
QWaitCondition condition;
QQueue ready;
Producer *producer = new Producer(&mutex, &condition);
Consumer *consumer = new Consumer(&mutex, &condition);
producer->setReady(&ready);
consumer->setReady(&ready);
producer->start();
consumer->start();
QThread::sleep(5);
producer->stop();
consumer->stop();
producer->wait();
consumer->wait();
delete producer;
delete consumer;
return a.exec();
}
“`
在这个例子中,我们有一个 Producer 线程通过异步的方式生成数据,并将它们存储在队列 ready 中。一个 Consumer 线程从队列 ready 中获取数据并处理。
结语
本文简要介绍了QWaitCondition的基本知识和使用方法。QWaitCondition可以与QMutex一起使用来实现线程同步,在多个线程之间进行通信。正如上述示例中的生产者-消费者模型,它可以帮助我们更轻松地编写多线程程序来实现复杂的操作。但是,在使用QWaitCondition时,我们需要注意避免死锁的问题。同时,由于QWaitCondition所使用的是条件变量,所以需要注意没有竞争条件出现。
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/283312.html