Qt 线程同步之 QWaitCondition

简述

本博用 QWaitCondition 实现了线程同步中的“生产者-消费者”模式。

  • 简述
  • 详述
  • 效果图
  • 关键知识
  • 源码
    • 类的创建
    • 类的使用
    • 源码下载

详述

  • 生产者线程生产数字,存放在 vector 中。消费者线程消耗数字。
  • 生产者线程先检测 vector 中的数字的总个数是否超出规定的限制(即代码中的 NUMBER_SIZE),超过限制则生产者线程阻塞,直到消费者线程发出 numberNotFull 条件才会进行下一步。接下来消费者线程会产生一个随机数添加到 vector 尾部,并发送numberNotEmpty 条件。
  • 消费者线程先检测 vector 中的数字个数是否为 0,为0的话,消费者线程阻塞,直到生产者线程发出 numberNotEmpty 条件才会进行下一步。接下来消费者线程取出 vector 中的第一个元素,发送给主线程。并发送 numberNotFull 条件。

效果图

Qt 线程同步之 QWaitCondition_第1张图片

关键知识

理解 QWaitCondition 的重点在于理解其 wait 函数;此处一定要详细地看文档,摘录如下:

函数原型:

bool QWaitCondition::wait(QMutex *lockedMutex, unsigned long time = ULONG_MAX)

释义:

Releases the lockedMutex and waits on the wait condition. The lockedMutex must be initially locked by the calling thread. If lockedMutex is not in a locked state, the behavior is undefined. If lockedMutex is a recursive mutex, this function returns immediately. The lockedMutex will be unlocked, and the calling thread will block until either of these conditions is met:
Another thread signals it using wakeOne() or wakeAll(). This function will return true in this case.
time milliseconds has elapsed. If time is ULONG_MAX (the default), then the wait will never timeout (the event must be signalled). This function will return false if the wait timed out.
The lockedMutex will be returned to the same locked state. This function is provided to allow the atomic transition from the locked state to the wait state.

源码

类的创建

testThread.h

#pragma once

#include 

class ThreadConsumer : public QThread
{
    Q_OBJECT

public:
    ThreadConsumer(QObject *parent);
    ~ThreadConsumer();
    void run() Q_DECL_OVERRIDE;
    bool threadStatus();
    void setThreadStatus(bool status);
signals:
    void sendToMainWindow(const int);
private:
    bool m_threadStatus;
};

class ThreadProducer : public QThread
{
    Q_OBJECT

public:
    ThreadProducer(QObject *parent);
    ~ThreadProducer();
    void run() Q_DECL_OVERRIDE;
    bool threadStatus();
    void setThreadStatus(bool status);
private:
    bool m_threadStatus;
};

testThread.cpp

#include "testThread.h"
#include
#include 
#include 
#include 

QWaitCondition numberNotFull;
QWaitCondition numberNotEmpty;
QMutex mutex;
QVector<int> vectInt;

const int NUMBER_SIZE = 3;

int generateRandomInteger(int min, int max);

ThreadConsumer::ThreadConsumer(QObject *parent)
    : QThread(parent)
{
    m_threadStatus = true;
}

ThreadConsumer::~ThreadConsumer()
{
}

void ThreadConsumer::run() 
{
    while (m_threadStatus)
    {
        mutex.lock();
        if (vectInt.isEmpty())
            numberNotEmpty.wait(&mutex);
        emit sendToMainWindow(vectInt.value(0));
        vectInt.pop_front();
        mutex.unlock();
        numberNotFull.wakeAll();
    }
}

void ThreadConsumer::setThreadStatus(bool status)
{
    m_threadStatus = status;
}

bool ThreadConsumer::threadStatus()
{
    return m_threadStatus;
}

//===================================================================
//类的分界线


ThreadProducer::ThreadProducer(QObject *parent)
    : QThread(parent)
{
    m_threadStatus = true;
}

ThreadProducer::~ThreadProducer()
{
}

void ThreadProducer::run()
{
    while (m_threadStatus)
    {
        mutex.lock();
        if (vectInt.size() > NUMBER_SIZE)
            numberNotFull.wait(&mutex);
        mutex.unlock();
        int number = generateRandomInteger(0, 1000);
        mutex.lock();
        vectInt.push_back(number);
        mutex.unlock();
        numberNotEmpty.wakeAll();
        sleep(1);//避免频繁刷新界面
    }
}

void ThreadProducer::setThreadStatus(bool status)
{
    m_threadStatus = status;
}

bool ThreadProducer::threadStatus()
{
    return m_threadStatus;
}

// 生成随机数 min:随机数的最小值,max:随机数的最大值
int generateRandomInteger(int min, int max)
{
    Q_ASSERT(min < max);
    // 加入随机种子。种子是当前时间距离0点0分0秒的秒数。
    // 每次启动程序,只添加一次种子,以做到数字真正随机。
    static bool seedStatus;
    if (!seedStatus)
    {
        qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
        seedStatus = true;
    }
    int nRandom = qrand() % (max - min);
    nRandom = min + nRandom;

    return nRandom;
}

类的使用

main.cpp

#include "testApp.h"
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    testApp w;
    w.show();
    return a.exec();
}

testApp.h

#pragma once

#include 
#include "ui_testApp.h"

class ThreadConsumer;
class ThreadProducer;

class testApp : public QMainWindow
{
    Q_OBJECT

public:
    testApp(QWidget *parent = Q_NULLPTR);
    ~testApp();

protected slots:
    void on_btnStart_clicked();
    void handleResult(const int);

private:
    Ui::testAppClass ui;
    ThreadConsumer* thdConsumer;
    ThreadProducer* thdProducer;
};

testApp.cpp

#include "testApp.h"
#include "testThread.h"

testApp::testApp(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    setWindowTitle(QStringLiteral("线程同步"));

    thdConsumer = new ThreadConsumer(this);
    thdProducer = new ThreadProducer(this);

    connect(thdConsumer, &QThread::finished, thdConsumer, &QObject::deleteLater);
    connect(thdConsumer, &ThreadConsumer::sendToMainWindow, this, &testApp::handleResult);
}

void testApp::on_btnStart_clicked()
{
    thdConsumer->setThreadStatus(true);
    thdConsumer->start();
    thdProducer->setThreadStatus(true);
    thdProducer->start();
}

void testApp::handleResult(const int number)
{
    ui.lineEdit->setText(QString::number(number));
}

testApp::~testApp()
{
    thdConsumer->setThreadStatus(false);
    thdConsumer->quit();
    thdConsumer->wait();
    thdProducer->setThreadStatus(false);
    thdProducer->quit();
    thdProducer->wait();
}

testApp.ui
Qt 线程同步之 QWaitCondition_第2张图片

源码下载

QWaitCondition-源码下载-【站内链接】

你可能感兴趣的:(Qt)