当前位置: 首页 > news >正文

【QT5 多线程示例】条件变量

文章目录

  • 条件变量
    • 使用 wakeOne()
    • 使用 wakeAll()

条件变量

QT的条件变量类是QWaitCondition,有wakeOne()wakeAll() 两个方法

  • wakeOne():仅唤醒一个等待的线程。
  • wakeAll():唤醒所有等待的线程。

使用 wakeOne()

https://github.com/BinaryAI-1024/QtStudy/tree/master/thread/conditionVariable

有 3 个工作线程 在 QWaitCondition 上等待,wakeOne() 只唤醒其中一个线程。

// main.cpp
#include <QCoreApplication>
#include <QThread>
#include <QTimer>
#include "myworker.h"

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    const int numThreads = 3;
    QThread* threads[numThreads];
    MyWorker* workers[numThreads];

    for (int i = 0; i < numThreads; ++i) {
        threads[i] = new QThread();
        workers[i] = new MyWorker();

        workers[i]->moveToThread(threads[i]);

        // 线程启动时,工作对象执行 doWork()
        QObject::connect(threads[i], &QThread::started, workers[i], &MyWorker::doWork);

        // 任务完成后退出线程的事件循环
        QObject::connect(workers[i], &MyWorker::finished, threads[i], &QThread::quit);

        // 任务完成后删除工作对象
        QObject::connect(workers[i], &MyWorker::finished, workers[i], &QObject::deleteLater);

        // 线程退出后删除线程对象
        QObject::connect(threads[i], &QThread::finished, threads[i], &QObject::deleteLater);

        threads[i]->start();
    }

    // 2 秒后唤醒所有线程
    QTimer::singleShot(2000, [=]() {
        workers[0]->startWork();  // 让所有 worker 线程醒来
    });

    return app.exec();
}

// myworker.h
#ifndef MYWORKER_H
#define MYWORKER_H

#include <QObject>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QDebug>

class MyWorker : public QObject {
    Q_OBJECT
public:
    explicit MyWorker(QObject *parent = nullptr);
    ~MyWorker();
signals:
    void finished();
public slots:
    void doWork();
    void startWork();

private:
    QMutex mutex;              // 每个实例都有一个互斥锁
    QWaitCondition condition;  // 每个实例都有一个条件变量
    bool ready = false;        // 每个实例都有一个标志变量
};

#endif // MYWORKER_H

// myworker.cpp
#include "myworker.h"

MyWorker::MyWorker(QObject *parent) : QObject(parent) {}

MyWorker::~MyWorker() {
    qDebug() << QThread::currentThread() << "Worker destroyed";
}

void MyWorker::doWork() {
    qDebug() << QThread::currentThread() << "Worker waiting...";

    {
        QMutexLocker locker(&mutex);  // 加锁
        while (!ready) {  // 等待被唤醒
            condition.wait(&mutex);
        }
    }


    qDebug() << QThread::currentThread() << "Worker processing...";
    QThread::msleep(2000);
    qDebug() << QThread::currentThread() << "Worker finished!";
    emit finished();
}


void MyWorker::startWork() {
    QMutexLocker locker(&mutex);
    ready = true;
    condition.wakeOne();  // 仅唤醒一个线程
}

运行结果

QThread(0x1481b00) Worker waiting...
QThread(0x1487b10) Worker waiting...
QThread(0x1487d58) Worker waiting...
QThread(0x1481b00) Worker processing...
QThread(0x1481b00) Worker finished!
QThread(0x1481b00) Worker destroyed

使用 wakeAll()

https://github.com/BinaryAI-1024/QtStudy/tree/master/thread/conditionVariableAll
有 3 个工作线程在 QWaitCondition 上等待,wakeAll() 同时唤醒所有线程。这需要将QMutexQWaitConditionready 声明为静态变量,在多个 MyWorker实例间共享。

// main.cpp
#include <QCoreApplication>
#include <QThread>
#include <QTimer>
#include "myworker.h"

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    const int numThreads = 3;
    QThread* threads[numThreads];
    MyWorker* workers[numThreads];

    for (int i = 0; i < numThreads; ++i) {
        threads[i] = new QThread();
        workers[i] = new MyWorker();

        workers[i]->moveToThread(threads[i]);

        // 线程启动时,工作对象执行 doWork()
        QObject::connect(threads[i], &QThread::started, workers[i], &MyWorker::doWork);

        // 任务完成后退出线程的事件循环
        QObject::connect(workers[i], &MyWorker::finished, threads[i], &QThread::quit);

        // 任务完成后删除工作对象
        QObject::connect(workers[i], &MyWorker::finished, workers[i], &QObject::deleteLater);

        // 线程退出后删除线程对象
        QObject::connect(threads[i], &QThread::finished, threads[i], &QObject::deleteLater);

        threads[i]->start();
    }

    // 2 秒后唤醒所有线程
    QTimer::singleShot(2000, [=]() {
        workers[0]->startWork();  // 让所有 worker 线程醒来
    });

    return app.exec();
}

// myworker.h
#ifndef MYWORKER_H
#define MYWORKER_H

#include <QObject>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QDebug>

class MyWorker : public QObject {
    Q_OBJECT
public:
    explicit MyWorker(QObject *parent = nullptr);
    ~MyWorker();
signals:
    void finished();
public slots:
    void doWork();
    void startWork();

private:
    static QMutex mutex;  // 互斥锁(多个 MyWorker 共享)
    static QWaitCondition condition;  // 等待条件(多个 MyWorker 共享)
    static bool ready;  // 共享的标志变量
};

#endif // MYWORKER_H
// myworker.cpp
#include "myworker.h"
#include <QMutexLocker>
// 共享变量初始化
QMutex MyWorker::mutex;
QWaitCondition MyWorker::condition;
bool MyWorker::ready = false;

MyWorker::MyWorker(QObject *parent) : QObject(parent) {}

MyWorker::~MyWorker() {
    qDebug() << QThread::currentThread() << "Worker destroyed";
}

void MyWorker::doWork() {
    qDebug() << QThread::currentThread() << "Worker waiting...";

    {
        QMutexLocker locker(&mutex);  // 加锁
        while (!ready) {  // 等待被唤醒
            condition.wait(&mutex);
        }
    }


    qDebug() << QThread::currentThread() << "Worker processing...";
    QThread::msleep(2000);
    qDebug() << QThread::currentThread() << "Worker finished!";
    emit finished();
}


void MyWorker::startWork() {
    QMutexLocker locker(&mutex);
    ready = true;
    condition.wakeAll();  // 唤醒所有等待的线程
}

运行结果

QThread(0xa9f1b00) Worker waiting...
QThread(0xa9f7fd8) Worker waiting...
QThread(0xa9f80d0) Worker waiting...
QThread(0xa9f1b00) Worker processing...
QThread(0xa9f80d0) Worker processing...
QThread(0xa9f7fd8) Worker processing...
QThread(0xa9f1b00) Worker finished!
QThread(0xa9f80d0) Worker finished!
QThread(0xa9f7fd8) Worker finished!
QThread(0xa9f1b00) Worker destroyed
QThread(0xa9f7fd8) Worker destroyed
QThread(0xa9f80d0) Worker destroyed

相关文章:

  • WPF TemplateBinding与TemplatedParent区别
  • CSS3:现代Web设计的魔法卷轴
  • 【深度学习总结】多模态推理分割:LISA代码详解
  • JVM中的垃圾回收算法
  • 模拟电子技术-基本放大电路
  • 前端调试技巧:console输出被禁时,用DOM输出调试信息
  • 洛谷 P10463 Interval GCD Solution
  • uniapp利用第三方(阿里云)实现双人视频/音频通话功能(附完整的项目代码)
  • uniapp开发中store的基本用法和模块化详解
  • CSS 中grid - template - areas属性的作用,如何使用它创建复杂的网格布局?
  • 探索 Vue 中的多语言切换:<lang-radio /> 组件详解!!!
  • 01 相机标定与相机模型介绍
  • wps 怎么显示隐藏文字
  • FFmpeg —— 中标麒麟系统下使用FFmpeg内核+Qt界面,制作完整功能音视频播放器(附:源码)
  • CI/CD基础知识
  • 【MySQL】create table和create tablespace语句
  • 安装node,配置npm, yarn, pnpm, bun
  • QCustomPlot入门
  • Vue从入门到荒废-常见问题及解决方案[基于Vue2]
  • Appium中元素定位之一组元素定位API
  • 用html5做的网站的原代码/青岛网站关键词优化公司
  • 景安网络网站建设教程/网络营销软文范例
  • 视频聊天室网站开发/阿里妈妈推广网站
  • 中山网站制作公司/如何查看网站权重
  • 中国建设银行洛阳分行官网站/今天全国31个省疫情最新消息
  • 网站制作的公司/提升关键词排名有哪些方法