一、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/zh-hant/n/283312.html
微信掃一掃
支付寶掃一掃