QT开发--多线程

news2024/10/23 13:32:54

第十四章 多线程

        QThread 是 Qt 中实现多线程编程的核心类,提供跨平台线程管理。

使用 QThread 有两种方法:

       1、 继承 QThread:重写 run() 方法,实现线程的具体操作。Qt4.8 之前较常用。

       2、 使用 QObjectmoveToThread():创建一个继承 QObject 的工作对象,使用 moveToThread() 将其移动到一个 QThread 对象中运行。官方推荐。

//当你调用moveToThread()时,
//你指定的QObject及其所有子对象将会在与该QThread对象相关联的线程中执行它们的槽函数。
void QObject::moveToThread(QThread *thread);

14.1 继承 QThread 的线程

        继承QThread是创建线程的一种方法。

        在这种方法中,只有重写的run()方法运行在子线程中,其他在类内定义的方法仍然在主线程中执行。用户需重写run()方法,并将耗时操作置于其中。

        用 connect关联 QThread类的对象的信号和 QWidget的槽函数。

14.1.1 应用实例

    // 告诉线程启动
    QThread::start();
    // 告诉线程退出  
    QThread::quit();  
    // 阻塞等待线程真正结束  
    QThread::wait();  

        本例展示了如何通过继承QThread类来创建和使用线程。在MainWindow类中,我们使用了一个按钮来启动线程,并在线程完成后接收其发送的信号。

#ifndef MAINWINDOW_H  // 防止头文件重复包含  
#define MAINWINDOW_H  
  
#include <QMainWindow>  // 引入QMainWindow类  
#include <QThread>     // 引入QThread类  
#include <QPushButton>  // 引入QPushButton类  
  
// 前向声明WorkerThread类  
class WorkerThread;  
  
class MainWindow : public QMainWindow {  
    Q_OBJECT  // 使用Qt的宏,支持信号槽机制  
public:  
    MainWindow(QWidget *parent = nullptr);  // 构造函数  
    ~MainWindow();  // 析构函数  
  
private:  
    WorkerThread *workerThread;  // 工作线程对象指针  
    QPushButton *pushButton;     // 按钮对象指针  
  
private slots:  
    void handleResults(const QString &result);  // 处理线程结果的槽函数  
    void pushButtonClicked();  // 按钮点击的槽函数  
};  
  
// WorkerThread类继承自QThread  
class WorkerThread : public QThread {  
    Q_OBJECT  // 使用Qt的宏,支持信号槽机制  
public:  
    WorkerThread(QWidget *parent = nullptr) { Q_UNUSED(parent); }  // 构造函数,忽略parent参数  
  
    // 重写run方法,线程在此方法中执行耗时操作  
    void run() override {  
        QString result = "线程开启成功";  // 定义结果字符串  
        sleep(2);  // 模拟耗时操作,延时2秒  
        emit resultReady(result);  // 发射结果准备好的信号  
        /*使用emit关键字发射一个信号时,该信号会被发送给所有与这个信号相连接的槽(slots)*/
    }  
  
signals:  
    // 声明一个信号,当线程完成工作时发射  
    void resultReady(const QString &s);  
};  
  
#endif // MAINWINDOW_H  // 头文件结束标志
#include "mainwindow.h"  // 引入MainWindow头文件  
  
// MainWindow构造函数,初始化UI和线程  
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {  
    // 创建并设置按钮  
    pushButton = new QPushButton("开启线程", this);  
    // 创建工作线程对象  
    workerThread = new WorkerThread(this);  
  
    // 连接工作线程的信号到MainWindow的槽函数  
    connect(workerThread, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));  
    // 连接按钮点击信号到MainWindow的槽函数  
    connect(pushButton, SIGNAL(clicked()), this, SLOT(pushButtonClicked()));  
}  
  
// MainWindow析构函数,处理线程关闭  
MainWindow::~MainWindow() {  
    // 告诉线程退出  
    workerThread->quit();  
    // 阻塞等待线程真正结束  
    workerThread->wait();  
}  
  
// 处理线程结果的槽函数  
void MainWindow::handleResults(const QString &result) {  
    // 使用qDebug输出线程结果  
    qDebug() << result;  
}  
  
// 按钮点击的槽函数  
void MainWindow::pushButtonClicked() {  
    // 检查线程是否已在运行,如果没有则启动线程  
    if (!workerThread->isRunning()) {  
        workerThread->start();  
    }  
}

        按钮点击后,QThread类start()函数开始运行,run()函数执行,

        2s后发送  emit resultReady(result);信号,触发槽函数打印结果。

14.2 继承 QObject 的线程

        继承QObject类并使用 QObject::moveToThread()方法。

        继承QObject类的方法更为灵活,因为它允许将一个QObject对象转移到另一个线程中执行。

14.2.1 应用实例

        mainWindow窗口类有 Worker:QObject成员,QThread成员

        Worker中定义任务,使用 QObject::moveToThread(&qthread)来代替重写QThread的run方法,使得线程可以执行这个任务

#ifndef MAINWINDOW_H  
#define MAINWINDOW_H  
  
#include <QMainWindow>  
#include <QThread>  
#include <QDebug>  
#include <QPushButton>  
#include <QMutexLocker>  
#include <QMutex>  
  
// 前向声明Worker类  
class Worker;  
  
class MainWindow : public QMainWindow {  
    Q_OBJECT  
  
public:  
    MainWindow(QWidget *parent = nullptr);  // 构造函数  
    ~MainWindow();  // 析构函数  
  
private:  
    QPushButton *pushButton1;  // 开始线程按钮  
    QPushButton *pushButton2;  // 打断线程按钮  
    QThread workerThread;      // 工作线程  
    Worker *worker;            // 工人类实例  
  
private slots:  
    void pushButton1Clicked();  // 开启线程槽函数  
    void pushButton2Clicked();  // 打断线程槽函数  
    void handleResults(const QString &); // 处理工作结果槽函数  
  
signals:  
    void startWork(const QString &); // 发送开始工作信号  
};  
  
// Worker类,用于处理耗时任务  
class Worker : public QObject {  
    Q_OBJECT  
  
private:  
    QMutex lock;        // 互斥锁,用于线程同步  
    bool isCanRun;      // 控制工作是否可以继续的标志位  
  
public slots:  
    void doWork1(const QString &parameter) {  
        isCanRun = true;  
        // 使用互斥锁保护共享资源,并在条件不满足时退出循环  
        while (true) {  
            QMutexLocker locker(&lock);  
            if (!isCanRun) break;  
        }  
        QThread::sleep(2); // 模拟耗时操作,秒  
  
        // 发射工作结果信号  
        emit resultReady(parameter + " doWork1 函数");  
        emit resultReady("打断 doWork1 函数"); // 通知工作已完成(此处设计可能不合理,通常只需在工作结束时发射一次信号)  
    }  
  
public:  
    void stopWork() {  
        qDebug() << "打断线程";  
        /*创建了一个 QMutexLocker 对象,
        并立即尝试锁定传递给它的 QMutex 对象(即 lock)。
        如果 lock 已经被另一个线程锁定,那么这行代码会阻塞当前线程,直到 lock 被释放为止。*/
        QMutexLocker locker(&lock);  
        isCanRun = false;  // 设置标志位,停止工作  
    }  
  
signals:  
    void resultReady(const QString &result); // 工作结果信号  
};  
  
#endif // MAINWINDOW_H
#include "mainwindow.h"  
  
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {  
    // 设置窗口和按钮的基本属性  
    this->setGeometry(0, 0, 800, 480);  
    pushButton1 = new QPushButton("开启线程", this);  
    pushButton2 = new QPushButton("打断线程", this);  
    pushButton1->setGeometry(300, 200, 80, 40);  
    pushButton2->setGeometry(400, 200, 80, 40);  
  
    // 实例化Worker对象,并将其移动到workerThread线程中  
    worker = new Worker;  
    worker->moveToThread(&workerThread);  
  
    // 连接信号和槽  
    connect(&workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));  
    connect(&workerThread, SIGNAL(finished()), &workerThread, SLOT(deleteLater()));  
    connect(this, SIGNAL(startWork(QString)), worker, SLOT(doWork1(QString)));  
    connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));  
    connect(pushButton1, SIGNAL(clicked()), this, SLOT(pushButton1Clicked()));  
    connect(pushButton2, SIGNAL(clicked()), this, SLOT(pushButton2Clicked()));  
}  
  
MainWindow::~MainWindow() {  
    // 打断线程并等待其结束  
    worker->stopWork();  
    workerThread.quit();  
    workerThread.wait(2000); // 阻塞等待2秒  
    qDebug() << "线程结束" << endl;  
}  
  
void MainWindow::pushButton1Clicked() {  
    if (!workerThread.isRunning()) {  
        workerThread.start();  
    }  
    emit startWork("正在运行");  
}  
  
void MainWindow::pushButton2Clicked() {  
    if (workerThread.isRunning()) {  
        worker->stopWork();  
    }  
}  
  
void MainWindow::handleResults(const QString &results) {  
    qDebug() << "线程的状态:" << results << endl;  
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2211536.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024-10-13 NO.1 Quest3 激活教程

文章目录 1 下载 Occlus 助手2 打开 quest 热点3 Quest3 连接 wifi4 详细文档5 参考教程 1 下载 Occlus 助手 ​ 网址&#xff1a;https://ochelper.xlemon.cn/home.html。 2 打开 quest 热点 ​ 下载 Occlus 助手后&#xff0c;双击 exe 文件打开。 ​ 过程中按照程序提示执…

各类排序详解

前言 本篇博客将为大家介绍各类排序算法&#xff0c;大家知道&#xff0c;在我们生活中&#xff0c;排序其实是一件很重要的事&#xff0c;我们在网上购物&#xff0c;需要根据不同的需求进行排序&#xff0c;异或是我们在高考完报志愿时&#xff0c;需要看看院校的排名&#…

【动手学深度学习】6.2 图像卷积(个人向笔记)

1. 互相关运算 严格来说&#xff0c;卷积层是一个错误的叫法&#xff0c;因为它本质上是互相关运算而不是卷积运算。我们暂时忽略通道看看二维图像数据和隐藏表示。那么输出大小可以表示为 我们自己实现一个二维互相关运算 2. 卷积层 卷积层中有两个参数&#xff1a;卷积核权…

Medieval Kingdom UI 中世纪王国AAA级UI游戏界面

这款中世纪王国风格的大型素材包包含大量绘图、图标、用户界面(UI)元素、完整的世界地图和文明图标。它将助您打造一款游戏,或为您的3D游戏增添亮点。您还可以为对话制作国王的动画,为4K游戏创建独特的面板和窗口。提供两种独特皮肤:经典(冷色调)和白金(暖色调)。 素…

国家基本药物目录数据库查询3种方法(2018、2012、2009年版)

国家基本药物目录是一份由国家卫生健康委员会等相关部门制定的药品清单&#xff0c;旨在满足国家公共卫生需求&#xff0c;保障基本医疗服务。该目录包括了多种药品&#xff0c;覆盖了不同的疾病治疗领域&#xff0c;如抗生素、心血管药物、神经系统药物、抗肿瘤药物、维生素和…

STM32 -- USB CDC 虚拟串口通信

本篇操作: 通过CubeMX Keil&#xff0c;配置STM32作为USB设备端&#xff0c;与电脑上位机进行通信&#xff08;CDC&#xff09;&#xff1b;通用带USB功能的 STM32 芯片 &#xff08;如F1、F4等&#xff0c;系统时钟配置不同&#xff0c;代码通用&#xff09;。 目录 一、 S…

[论文精读]Active and Semi-Supervised Graph Neural Networks for Graph Classification

论文网址&#xff1a;Active and Semi-Supervised Graph Neural Networks for Graph Classification | IEEE Journals & Magazine | IEEE Xplore英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若…

大数据-168 Elasticsearch 单机云服务器部署运行 详细流程

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

PyQt: QMessageBox Duplication

在使用 PyQt 的 QMessageBox 时&#xff0c;如果你遇到 消息框重复显示 或 QMessageBox 重复实例化 的问题&#xff0c;通常是因为消息框没有正确管理或关闭&#xff0c;或者消息框的创建和显示逻辑中存在重复调用。以下是一些常见原因和解决方案。 1、问题背景 在 PyQt 中使用…

无心剑七绝《泊院雕楼》

七绝泊院雕楼 清歌咏尽桂花香 泊院雕楼醉夕阳 逸兴无端飞万里 幽情宛转忆潇湘 2024年10月13日 平水韵七阳平韵 这首七绝《泊院雕楼》以清新脱俗的语言&#xff0c;描绘了一幅宁静致远的画面。 首句“清歌咏尽桂花香”&#xff0c;以“清歌”起兴&#xff0c;形象地描绘了桂花香…

C++——类和对象(三)

一.赋值运算符 1.运算符重载 (1) 运算符重载是具有特殊名字的函数&#xff0c;他的名字是由operator和后面要定义的运算符共同构成。和其他函数一样&#xff0c;它也具有其返回类型和参数列表以及函数体。 (2) 重载运算符函数的参数个数和该运算符作用的运算对象数量一样多。…

React.createRef(),React.forwardRef(),forwardRef()结合next.js的link进行路由跳转

码云https://gitee.com/skyvilm/react-next.js 1.React.createRef() 作用&#xff1a;获取dom元素 使用 import React,{Component} from react export default class Index extends Componen{ constructor(props){ super(props) this.myrefReact.createRef(); //创建节点 } c…

如何批量从sql语句中提取表名

简介 使用的卢易表 的提取表名功能&#xff0c;可以从sql语句中批量提取表名。采用纯文本sql语法分析&#xff0c;无需连接数据库&#xff0c;支持从含非sql语句的文件文件中提取&#xff0c;支持各类数据库sql语法。 特点 快&#xff1a;从成百个文件中提取上千个表名只需1…

集成方案 | 借助 Microsoft Copilot for Sales 与 Docusign,加速销售流程!

加速协议信息提取&#xff0c;随时优化邮件内容~ 在当今信息爆炸的时代&#xff0c;销售人员掌握着丰富的数据资源。他们能够通过 CRM 平台、电子邮件、合同库以及其他多种记录系统&#xff0c;随时检索特定个人或组织的关键信息。这些数据对于销售沟通至关重要。然而&#x…

【端到端】CVPR 2023最佳论文:UniAD解读

作者&#xff1a;知乎一根呆毛授权发布 传统的端到端网络是用多个小model串起来&#xff0c;但这会有误差累积的问题&#xff0c;因此我们提出了UniAD&#xff0c;一个综合框架&#xff0c;把所有任务整合到一个网络。整一个网络都是为planner而进行设计的。 Introduction a传…

SQL性能优化指南:如何优化MySQL多表join场景

目录 多表join问题SQL 这里解释下 Using join buffer (Block Nested Loop)&#xff1a; 对性能产生的影响&#xff1a; 三种join算法介绍 join操作主要使用以下几种算法&#xff1a; &#xff08;1&#xff09;Nested Loop Join &#xff08;2&#xff09;Block Nested …

生信服务器配置:优化生物信息学数据处理的最佳实践

介绍 在生物信息学研究中&#xff0c;处理和分析大规模数据集&#xff08;如基因组、转录组和蛋白质组数据&#xff09;需要强大的计算资源和精确的服务器配置。生信服务器配置的优化可以显著提高数据处理的效率和结果的准确性。本文将探讨生信服务器配置的关键要素&#xff0…

【LeetCode热题100】分治-快排

本篇博客记录分治快排的4道题目&#xff1a;颜色分类、排序数组、数组中的第K个最大元素、数组中最小的N个元素&#xff08;库存管理&#xff09;。 class Solution { public:void sortColors(vector<int>& nums) {int n nums.size();int left -1,right n;for(int…

【实战项目】——Boost搜索引擎(五万字)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、项目的相关背景 1.1、什么是Boost库&#xff1f; 1.2、什么是搜索引擎&#xff1f; 1.3、为什么要做Boost库搜索引擎&#xff1f; 二、搜索引擎的宏观原…

VirtualBOX虚拟机提高速度,鼠标卡顿解决——未来之窗数据恢复

一、刚安装完操作系统&#xff0c;鼠标操作不灵敏 需要安装系统增强 二、系统增强作用 1.鼠标丝滑 2.文件共享 3.可以共享剪贴板 三、安装步骤-设备-安装增强 四、安装步骤-设备-选择光驱 五、安装增强软件然后重启 六、阿雪技术观 拥抱开源与共享&#xff0c;见证科技进…