Qt下多线程的四种使用方法总结及代码示例

news2024/12/26 21:51:42

文章目录

  • 前言
  • 一、继承QThread,重写run()函数
  • 二、继承QObject,使用moveToThread()函数
  • 三、继承QRunnable,重写run()函数,使用QThreadPool线程池
  • 四、使用QtConcurrent的run()函数
  • 五、示例代码
  • 六、下载链接
  • 总结


前言

在之前的Qt开发工作中,发现多线程的使用比较常见,这里将自己之前经历以及参考其它博文后获取的经验,对Qt下实现多线程的几种方式进行总结,并结合相应的示例,以便大家学习,如有错误之处,欢迎大家批评指正。

1.继承QThread,重写run()函数;
2.继承QObject,使用moveToThread()函数;
3.继承QRunnable,重写run()函数,使用QThreadPool线程池;
4.使用QtConcurrent的run()函数;

项目效果
依次点击界面上的四个groupBox中的Start按钮,可以看到下图的打印输出,通过线程号可以看到程序成功启动了四条线程,另外再次点击的话,QRunnable及QtConcurrent的方式可以再开启新的线程,所能开启的线程数量以当前线程池的设置有关。
请添加图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、继承QThread,重写run()函数

1.qthreadrun.h

#ifndef QTHREADRUN_H
#define QTHREADRUN_H

#include <QThread>
#include <QDebug>

class QThreadRun : public QThread
{
    Q_OBJECT

public:
    QThreadRun();
    ~QThreadRun();

    void setSwitch(bool flag);
    void run();

private:
    bool startFlag;
};
#endif // QTHREADRUN_H

2.qthreadrun.cpp

#include "qthreadrun.h"

QThreadRun::QThreadRun()
{
    startFlag = false;
}

QThreadRun::~QThreadRun()
{

}

void QThreadRun::setSwitch(bool flag)
{
    startFlag = flag;
}

void QThreadRun::run()
{
    while(startFlag)
    {
        qDebug()<<"QThreadRun子线程号:"<<QThread::currentThread();
        QThread::msleep(1000);   //延时1000ms
    }
}

二、继承QObject,使用moveToThread()函数

1.qmovetothread.h

#ifndef QMOVETOTHREAD_H
#define QMOVETOTHREAD_H

#include <QObject>
#include <QThread>
#include <QDebug>

class QMoveToThread : public QObject
{
    Q_OBJECT

public:
    QMoveToThread();
    ~QMoveToThread();

    void setSwitch(bool flag);

public slots:
    void slot_moveToThread();

private:
    bool startFlag;
};
#endif // QMOVETOTHREAD_H

2.qmovetothread.cpp

#include "qmovetothread.h"

QMoveToThread::QMoveToThread()
{
    startFlag = false;
}

QMoveToThread::~QMoveToThread()
{

}

void QMoveToThread::setSwitch(bool flag)
{
    startFlag = flag;
}

void QMoveToThread::slot_moveToThread()
{
    while(startFlag)
    {
        qDebug()<<"QMoveToThread子线程号:"<<QThread::currentThread();
        QThread::msleep(1000);
    }
}

三、继承QRunnable,重写run()函数,使用QThreadPool线程池

1.qrunnablerun.h

#ifndef QRUNNABLERUN_H
#define QRUNNABLERUN_H

#include <QRunnable>
#include <QThread>
#include <QDebug>

class QRunnableRun : public QRunnable
{
public:
    QRunnableRun();
    ~QRunnableRun();

    void setSwitch(bool flag);
    void run();

private:
    bool startFlag;
};
#endif // QRUNNABLERUN_H

2.qrunnablerun.cpp

#include "qrunnablerun.h"

QRunnableRun::QRunnableRun()
{
    startFlag = false;
}

QRunnableRun::~QRunnableRun()
{

}

void QRunnableRun::setSwitch(bool flag)
{
    startFlag = flag;
}

void QRunnableRun::run()
{
    while(startFlag)
    {
        qDebug()<<"QRunnableRun子线程号:"<<QThread::currentThread();
        QThread::msleep(1000);
    }
}

四、使用QtConcurrent的run()函数

1.在工程文件.pro文件中添加下面这句代码

QT   += concurrent

2.添加头文件

#include <QtConcurrent>

3.使用方式

...
//详细代码见下文
QtConcurrent::run(this,&Widget::myQtConcurrentRun);
...

五、示例代码

1.QThreadTest.pro

QT   += core gui
QT   += concurrent

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
    main.cpp \
    qmovetothread.cpp \
    qrunnablerun.cpp \
    qthreadrun.cpp \
    widget.cpp

HEADERS += \
    qmovetothread.h \
    qrunnablerun.h \
    qthreadrun.h \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

2.widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QThreadPool>
#include <QtConcurrent>
#include "qthreadrun.h"
#include "qmovetothread.h"
#include "qrunnablerun.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void initThread();

    void setSwitch(bool flag);
    void myQtConcurrentRun();
    void myMainRun();

signals:
    void signal_moveToThread();

private slots:
    void on_pb_start_clicked();
    void on_pb_stop_clicked();
    void on_pb_start_2_clicked();
    void on_pb_stop_2_clicked();
    void on_pb_start_3_clicked();
    void on_pb_stop_3_clicked();
    void on_pb_start_4_clicked();
    void on_pb_stop_4_clicked();
    void on_pb_test_clicked();

private:
    Ui::Widget *ui;

    //QThreadRun
    QThreadRun *m_QThreadRun;

    //QMoveToThread
    QThread *m_QThread;
    QMoveToThread *m_QMoveToThread;

    //QRunnableRun
    QThreadPool *m_QThreadPool;
    QRunnableRun *m_QRunnableRun;

    //QtConcurrentRun
    bool startFlag;
};
#endif // WIDGET_H

3.widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->initThread();
}

Widget::~Widget()
{
    delete ui;
}

void Widget::initThread()
{
    //main
    qDebug()<<"Widget主线程号:"<<QThread::currentThread();

    //QThreadRun
    m_QThreadRun = new QThreadRun();

    //QMoveToThread
    m_QThread = new QThread(this);
    m_QMoveToThread = new QMoveToThread();
    connect(this,SIGNAL(signal_moveToThread()),m_QMoveToThread,SLOT(slot_moveToThread()),Qt::UniqueConnection);
    m_QMoveToThread->moveToThread(m_QThread);
    m_QThread->start();

    //QRunnableRun
    m_QThreadPool = new QThreadPool();
    m_QThreadPool->setMaxThreadCount(3);   //设置非全局线程池可容纳线程个数为3个
    m_QRunnableRun = new QRunnableRun();

    //QtConcurrentRun
    startFlag = false;
    //qDebug()<<QThreadPool::globalInstance()->maxThreadCount();   //获取全局线程池最大线程个数
    //QThreadPool::globalInstance()->setMaxThreadCount(10);        //设置全局线程池可容纳线程个数

}

void Widget::setSwitch(bool flag)
{
    startFlag = flag;
}

void Widget::myQtConcurrentRun()
{
    while(startFlag)
    {
        qDebug()<<"QtConcurrent子线程号"<<QThread::currentThread();
        QThread::msleep(1000);
    }
}

void Widget::myMainRun()
{
    while(startFlag)
    {
        qDebug()<<"当前线程号"<<QThread::currentThread();
        QThread::msleep(1000);
    }
}

//QThreadRun
void Widget::on_pb_start_clicked()
{
    m_QThreadRun->setSwitch(true);
    m_QThreadRun->start();
}

void Widget::on_pb_stop_clicked()
{
    m_QThreadRun->setSwitch(false);
}

//QMoveToThread
void Widget::on_pb_start_2_clicked()
{
    m_QMoveToThread->setSwitch(true);
    //m_QMoveToThread->slot_moveToThread();   不能直接调用处理函数,函数还是在主线程中运行
    emit signal_moveToThread();   //发送信号启动子线程处理函数
}

void Widget::on_pb_stop_2_clicked()
{
    m_QMoveToThread->setSwitch(false);
}

//QRunnableRun
void Widget::on_pb_start_3_clicked()
{
    m_QRunnableRun->setSwitch(true);

    //全局线程池方式
    //QThreadPool::globalInstance()->start(m_QRunnableRun);
    //qDebug()<<"全局线程池当前线程数:"<<QThreadPool::globalInstance()->activeThreadCount();   //当前活动的线程个数

    //非全局线程池方式
    m_QThreadPool->start(m_QRunnableRun);
    qDebug()<<"非全局线程池当前线程数:"<<m_QThreadPool->activeThreadCount();   //当前活动的线程个数

}

void Widget::on_pb_stop_3_clicked()
{
    m_QRunnableRun->setSwitch(false);
}

//QtConcurrentRun
void Widget::on_pb_start_4_clicked()
{
    setSwitch(true);
    QtConcurrent::run(this,&Widget::myQtConcurrentRun);
    qDebug()<<"QtConcurrentRun当前线程数:"<<QThreadPool::globalInstance()->activeThreadCount();   //当前活动的线程个数
}

void Widget::on_pb_stop_4_clicked()
{
    setSwitch(false);
}

//不使用多线程的对比测试,界面卡死
void Widget::on_pb_test_clicked()
{
    setSwitch(true);
    myMainRun();
}

4.widget.ui
请添加图片描述

六、下载链接

我的示例百度网盘链接:https://pan.baidu.com/s/1hpcXFA2vahZ0WV3pRUfqXQ
提取码:xxcj


总结

在上述实现多线程的方法中,可以看到使用QtConcurrent的run()函数是不需要继承类,也不需要重写函数的,使用起来比较方便,需要注意的一点是,通过该方式获取的线程是来自QThreadPool池,如果QThreadPool池中没有空闲的线程,该线程可能不会直接执行。使用QRunnable的run()的时候可以看到有全局线程池和非全局线程池方式来进行start,其中的全局线程池跟QtConcurrent方法的QThreadPool是同一个,这里有几个关于线程池的函数打印:
QThreadPool::globalInstance()->maxThreadCount(); //获取线程池最大线程个数
QThreadPool::globalInstance()->setMaxThreadCount(10); //设置线程池可容纳线程个数
QThreadPool::globalInstance()->activeThreadCount(); //当前线程池活动的线程个数
有关于Qt下多线程几种方式的优缺点等详细内容,可以查看参考文章。


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

参考博客:
Qt的4种多线程实现方式
Qt几种多线程的实现

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

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

相关文章

时间序列分析的基本流程(R语言版——实验篇)

数据处理 1.导入数据&#xff08;.csv&#xff09; 能导入绝大所数形式的格式文件 ex52<-read.table("C:\\Users\\33035\\Desktop\\习题5.2数据.txt",headerT,fileEncoding GBK) #header &#xff1a;T:表示留第一行 #fileEncoding:有中文时最好改为GBK 2.对数…

MySQL---DDL

MySQL简介DDL操作 文章目录MySQL简介DDL操作数据库分类关系型数据库&#xff08;SQL&#xff09;非关系型数据库&#xff08;NOSQL&#xff09;区别DBMSMySQL简介概念特点MySQL运行机制SQL通用语法结构化查询语言分类DDL操作数据库操作表查询创建数据类型数值类型字符串类型日期…

入行测试已经4年了 ,进阿里后迷茫了3个月,做完这个项目我决定离职....

转行测试 我是大专非计科&#xff0c;我转行之前从事的工作是商场管理&#xff0c;努力了4年左右的时间才做到楼层经理&#xff0c;但是工资太低并且事情太多&#xff0c;薪资才6K。 更多的是坚定了自己的想法&#xff0c;我要改变自己 恰好有几个大学同学在互联网公司工作&a…

微电网重构|基于群稀疏性的机会约束微电网重构(Matlab代码和Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清…

python算法对音频信号处理Sonification :Gauss-Seidel迭代算法

可以将44.1kHz单通道.wav文件中的一秒读取到长度为44100的数组&#xff08;称为b&#xff09;中。给定矩阵A&#xff0c;我们寻求系统Ax b的解。通过Gauss-Seidel的迭代&#xff0c;向量如果我们将b记录的录音&#xff0c;则将一些白噪声作为我们的初始猜测&#xff0c;并在每…

JVM常见面试题

目录 一、JVM内存划分 二、JVM类加载 1、什么是类加载 2、类加载的过程 2.1 加载 2.2 连接 2.3 初始化 3、何时触发类加载 4、双亲委派模型 4.1 什么是双亲委派模型 4.2 双亲委派模型的优点 三、JVM的垃圾回收机制 1、什么是GC 2、GC回收哪部分内存 3、判定垃圾…

# Monaco Editor 使用

Monaco Editor 使用 文章目录Monaco Editor 使用安装依赖版本问题vue2Vue3webpack-dev-servermonaco-editor-webpack-pluginVersion Matrix集成步骤Vue2 配置 monaco-editor-webpack-plugin 插件Vue3 vue.config.js测试页面实例属性说明支持的语言类型报错解决控制台报错效果图…

自适应滤波器更新算法-EP2

文章目录1、变步长 SC-MPNLMS 频域分块算法1.1 算法原理1.2 算法代码1.3 算法优缺点2、集成多种自适应滤波算法的回声消除器1.1 算法原理1.2 算法代码1.3算法优缺点1.4 算法自适应准则3、新的变步长的LMS自适应滤波算法3.1算法原理3.2算法代码3.3算法优缺点参考文献本文接上一篇…

钉钉小程序入门3—钉钉扫码登录PC端网站

第一部分、准备材料&#x1f332; 公网环境 老版钉钉扫码中必须要配置一个域名才可以调试&#xff0c;新版支持IP配置调了。我是手机打开热点&#xff0c;电脑连接热点进行调试的&#xff0c;比老版要方便了不少。 查看本机IP地址方法&#xff1a; 如果使用的Windows&#xff…

MySQL高可用复制管理工具 —— Orchestrator使用

Orchestrator介绍 Orchestrator&#xff08;orch&#xff09;&#xff1a;go编写的MySQL高可用性和复制拓扑管理工具&#xff0c;支持复制拓扑结构的调整&#xff0c;自动故障转移和手动主从切换等。后端数据库用MySQL或SQLite存储元数据&#xff0c;并提供Web界面展示MySQL复…

docker学习笔记2(狂神)

Docker的常用命令 然后我们来学我们最重要的镜像命令&#xff1a; docker images 查看所有本地的主机上的镜像 docker search搜索镜像&#xff1a; docker pull下载镜像&#xff1a; docker pull 镜像名[:tag] 指定版本下载&#xff1a; docker rmi删除镜像&#xff1a; 批量…

[附源码]Python计算机毕业设计Django市场摊位管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

m基于遗传优化的不同等级电动汽车充电站的选址方案matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 作为电动汽车的普及与推广&#xff0c;必要的基础配套服务设施、充电站的建设位置和选址规划对整体行业的发展起着重要的意义&#xff0c;本文中提出了一个不同等级电动汽车充电站的选址与求解算…

Zebec联合Visa推出实体借记卡持续利好生态,$ZBC表现强劲

Zebec生态从今年年初开始&#xff0c;持续的释放利好提振市场信心。此前&#xff0c;Zebec曾以 10 亿美元的完全稀释估值筹集了 850 万美元&#xff0c;该轮融资投资者包括 Circle Ventures、Shima 和 Resolute等知名 Web3 投资机构。这是 Zebec Protocol 继今年年初获得 2800 …

计算机系统基本概念

1.计算机的硬件结构 早期的计算机没有很复杂的图形功能&#xff0c;CPU的核心频率也不高&#xff0c;跟内存的频率一样&#xff0c;它们都是直接连接在同一个总线&#xff08;Bus&#xff09; 上的。由于IO设备诸如显示设备、键盘、软盘和磁盘等速度与CPU和内存相比还是慢很多…

QT:布局管理器消息盒子对话框

让组件在水平和垂直方向对齐 有三种常用布局管理器&#xff1a; 水平&#xff0c;QHBoxLayout 垂直&#xff0c;QVBoxLayout 网格&#xff0c;QGridLayout(使布局好的界面嵌套到主窗口) 1.让组件大小固定 修改属性&#xff1a;minimusize&#xff0c;maxmumsize 最小和最大组件…

使用setuptools构建python包

python包分发方式 源码包分发&#xff1a; 源码包安装过程是先解压&#xff0c;再编译。最后才安装&#xff0c;所以其是跨平台的&#xff0c;由于每次安装都需要进行编译&#xff0c;相对于二进制包安装方式来说安装速度较慢。 解压——编译——安装 源码包本质上是一个压缩…

CDGA|2023年数据治理发展前景预测步骤

CDGA|2023年数据治理发展前景预测步骤 数据治理发展前景预测&#xff0c;就是在数据治理市场调查获得的各种信息和资料的基础上&#xff0c;运用科学的预测技术和方法&#xff0c;对影响数据治理市场供求变化的诸因素进行调查研究&#xff0c;分析和预见数据治理发展趋势&…

《解构领域驱动设计》读书笔记

文章目录书籍信息开篇软件复杂度剖析复杂系统理解能力预测能力领域驱动设计概览基本概念控制软件复杂度领域驱动设计统一过程现存的不足领域驱动设计统一过程全局分析问题空间探索全局分析的 5W 模型高效沟通高效协作商业模式画布业务流程图服务蓝图用例图事件风暴学习循环价值…

windows系统下mysql的主从复制

使用一台物理机实现mysql的主从复制功能。 准备&#xff1a; 1、操作系统&#xff1a;Windows Server 2016 Standard 2、下载mysql免安装包&#xff1a; https://downloads.mysql.com/archives/get/p/23/file/mysql-5.6.17-winx64.zip 安装maser 1、解压mysql压缩包&…