【QT】——多线程的使用

news2024/12/23 3:09:12

目录

基本概念

1.线程类QThread

1.1信号和槽

1.2静态函数

1.3 任务处理函数

2.实例

第一种方式

第二种方式

基本概念

  1. 默认的线程在Qt中称之为窗口线程,也叫主线程,负责窗口事件处理或者窗口控件数据的更新
  2. 子线程负责后台的业务逻辑处理,子线程中不能对窗口对象做任何操作,这些事情需要交给窗口线程处理
  3. 主线程和子线程之间如果要进行数据的传递,需要使用Qt中的信号槽机制 

1.线程类QThread

Qt 中提供了一个线程类,通过这个类就可以创建子线程了,Qt 中一共提供了两种创建子线程的方式,后边会依次介绍其使用方式

// QThread 类常用 API
// 构造函数
QThread::QThread(QObject *parent = Q_NULLPTR);
// 判断线程中的任务是不是处理完毕了
bool QThread::isFinished() const;
// 判断子线程是不是在执行任务
bool QThread::isRunning() const;

// Qt中的线程可以设置优先级
// 得到当前线程的优先级
Priority QThread::priority() const;
void QThread::setPriority(Priority priority);
优先级:
    QThread::IdlePriority         --> 最低的优先级
    QThread::LowestPriority
    QThread::LowPriority
    QThread::NormalPriority
    QThread::HighPriority
    QThread::HighestPriority
    QThread::TimeCriticalPriority --> 最高的优先级
    QThread::InheritPriority      --> 子线程和其父线程的优先级相同, 默认是这个
// 退出线程, 停止底层的事件循环
// 退出线程的工作函数
void QThread::exit(int returnCode = 0);
// 调用线程退出函数之后, 线程不会马上退出因为当前任务有可能还没有完成, 调回用这个函数是
// 等待任务完成, 然后退出线程, 一般情况下会在 exit() 后边调用这个函数
bool QThread::wait(unsigned long time = ULONG_MAX);

1.2信号和槽

// 和调用 exit() 效果是一样的
// 代用这个函数之后, 再调用 wait() 函数
[slot] void QThread::quit();
// 启动子线程
[slot] void QThread::start(Priority priority = InheritPriority);
// 线程退出, 可能是会马上终止线程, 一般情况下不使用这个函数
[slot] void QThread::terminate();

// 线程中执行的任务完成了, 发出该信号
// 任务函数中的处理逻辑执行完毕了
[signal] void QThread::finished();
// 开始工作之前发出这个信号, 一般不使用
[signal] void QThread::started();

1.3静态函数

// 返回一个指向管理当前执行线程的QThread的指针
[static] QThread *QThread::currentThread();
// 返回可以在系统上运行的理想线程数 == 和当前电脑的 CPU 核心数相同
[static] int QThread::idealThreadCount();
// 线程休眠函数
[static] void QThread::msleep(unsigned long msecs);	// 单位: 毫秒
[static] void QThread::sleep(unsigned long secs);	// 单位: 秒
[static] void QThread::usleep(unsigned long usecs);	// 单位: 微秒

1.4 任务处理函数

// 子线程要处理什么任务, 需要写到 run() 中
[virtual protected] void QThread::run();

2.实例

1.点击开始,创建一个生产线程,随机生成10000个数值。

2.通过信号将数组发送给主线程,并显示到窗口上

ui界面:

执行效果:

 

第一种方式

  1. 自定义一个类,并继承 QT 中的线程类 QThread
  2. 在自定义类中重写 run 方法,run函数需要在protected中,在该函数内部编写子线程要处理的具体的业务流程
  3. 在主线程中创建子线程对象
  4. 调用start()方法启动子线程

mythread.hpp        

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include<QThread>
class mythread : public QThread
{
    Q_OBJECT
public:
    explicit mythread(QObject *parent = nullptr);

signals:
     //自定义信号,将QVector<int>发送出去
     void sendVector(QVector<int> v);
public slots:

protected:
    void run(); //线程运行的函数
    int num=10000; 
};

#endif // MYTHREAD_H

 mythread.cpp

#include "mythread.h"
#include<QElapsedTimer>
#include<QVector>
#include<QDebug>
mythread::mythread(QObject *parent) : QThread(parent)
{}

void mythread::run(){
    QElapsedTimer time;
    time.start();
    QVector<int> vector;
    //生成10000个随机数
    for(int i=0;i<num;i++){
        int tmp=rand()%100000;
        vector.push_back(tmp);
    }
    sendVector(vector);

    int curtime=time.elapsed();
    qDebug()<<"生成随机数消耗时间"<<curtime;
}

//QElapsedTimer是一个timer对象,用来统计时间,从start函数开始计时,elapsed返回时间

 mainWindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    mythread* t=new mythread();

    
    //将子线程发送的sendVector信号 给关联起来
    connect(t,&mythread::sendVector,this,[=](QVector<int> v){
        for(int i=0;i<v.size();i++){

            ui->rand_text->appendPlainText(QString::number(v[i]));
        }

    });
    //点击启动按钮,启动线程
    connect(ui->start_button,&QPushButton::clicked,this,[=](){
        //启动线程
        t->start();
    });

}

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

//知识点:
//appendPlainText接口是在文本框中展示数据
//Qstring::number()接口是将 int类型转换为 QString类型

第二种方式

  1. 创建一个任务类task,这个任务类继承QObject
  2. 在任务类中写一个working的函数,函数内部写处理业务的流程
  3. 创建一个QThread 对象 和一个 task任务类对象
  4. 让task对象 使用函数 moveToThread 指定 线程 执行该 任务
  5. 通过信号或者某种方式将 task对象中 working运行
  6. 调用线程start函数,则 线程开始执行任务类中的 working函数。

task.h文件

#ifndef TASK_H
#define TASK_H
#include<QObject>
#include<QVector>
class task:public QObject
{
    Q_OBJECT
 signals:
    void sendVector(QVector<int> v);
    void begin(int num);
public:
    task();
    ~task();
    void working(int num);
};

#endif // TASK_H

task.cpp

#include "task.h"
#include<QElapsedTimer>
#include<QDebug>
task::task()
{}

task::~task(){
}

void task::working(int num){
    QElapsedTimer time;
    time.start();
    //生成10000个随机数
    QVector<int> vector;
    for(int i=0;i<num;i++){
        int tmp=rand()%100000;
        vector.push_back(tmp);
    }
    sendVector(vector);

    int curtime=time.elapsed();
    qDebug()<<"生成随机数消耗时间"<<curtime;
}

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QThread>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QThread* t=new QThread;
    task* t1=new task;
    
    //将任务绑定到线程t上
    t1->moveToThread(t);
    
    connect(t1,&task::sendVector,this,[=](QVector<int> v){
        for(int i=0;i<v.size();i++){
            ui->rand_text_3->appendPlainText(QString::number(v[i]));
        }

    });

    connect(t1,&task::begin,t1,&task::working);
    //点击启动按钮,启动线程
    connect(ui->start_button_3,&QPushButton::clicked,this,[=](){
        //启动线程
        emit t1->begin(10000);//触发working流程开始执行
        t->start();//触发线程开始执行
    });

}

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

第二种方式更灵活,更加容易维护。

 运行过程中出现的问题:

 如果上面这种情况,则需要在main函数的最前面加上 qRegisterMetaType 对象,声明某种类型是可以通过 信号传递给槽函数。

格式: qRegisterMetaType<类型.("类型")

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

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

相关文章

Rocky Linux能否通过其他方法合法地获得RHEL源代码?让我们一起来看看吧

在红帽公司限制对RHEL源代码的访问后&#xff0c;Rocky Linux寻找了替代方案来确保他们可以继续获取所需的源代码并行使他们的权利。他们认为这种限制违反了开源的精神和目的&#xff0c;因此积极寻求解决方案&#xff0c;以维护他们对开源软件的承诺。那么Rocky Linux能否通过…

AOM、VTM初体验及安装tensorflow

AOM、VTM初体验 Cmake cmake的定义是什么 &#xff1f;-----高级编译配置工具 当你用不同的语言或者编译器开发一个项目&#xff0c;各就各位code完之后要生成最终的输出&#xff08;dll 或执行文件&#xff09;&#xff0c;这时候就尴尬了&#xff0c;你要手动去MingGW或者…

Kotlin 1.9 新特性预览:data object (数据单例)

前言 data object (数据单例) 是 Kotlin 1.9 中预定引入的新特性 &#xff0c;但其实从 1.7.20 开始就可以预览了。启动预览需要在 gradle 中升级 KotlinCompileVersion&#xff1a; tasks.withType<KotlinCompile> {kotlinOptions.languageVersion "1.9" }…

四、交换网络实验3——VTP配置

更多网络基础内容可见: 网络基础学习目录及各章节指引 4.6.3 VTP配置 实验目的 学习思科私有协议VTP的配置方法,观察VTP三种工作模式的通信方式 实验工具 Cisco Packet Tracer Student 软件 实验环境 安装模拟器的Windows系统 实验步骤 第一步:根据拓扑图,选择三台同…

老胡的周刊(第097期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 Chat2DB[2] Chat2DB 是一款有开源免费的智能…

二分查找--图文详解

二分查找 1. 什么是二分查找2. 原理3. 例子3.1 当数组长度为奇数3.1 当数组长度为偶数3.3 实现过程 4. 顺序查找与二分查找的区别结束语 1. 什么是二分查找 二分查找也称折半查找&#xff0c;是在一组有序(升序/降序)的数据中查找一个元素&#xff0c;它是一种效率较高的查找方…

chatgpt赋能python:重新配置PyCharm,让你的Python编程更加高效

重新配置PyCharm&#xff0c;让你的Python编程更加高效 PyCharm是一个流行的Python集成开发环境&#xff0c;被广泛用于Python编程。但是&#xff0c;有时候我们需要重新配置PyCharm以适应特定的工作需求或优化其性能&#xff0c;这篇文章将讨论如何重新配置PyCharm&#xff0…

K8S安全管理

1 安全管理 1.1 安全框架 1.1.1 认证框架 学习目标 这一节&#xff0c;我们从 基础知识、认证流程、小结 三个方面来学习。 基础知识 资源操作 用户访问k8s业务应用的流程&#xff1a;方法一&#xff1a;无需api_server认证用户 -- ingress|service -- pod方法二&#xf…

Transformer面试题总结

1.框架 Transformer和seq2seq一样由解码器和编码器组成&#xff0c;用多头注意力替换编码器和解码器架构中最常用的循环层 1.1 编码器&#xff1a;编码器有一堆N6的相同层组成&#xff0c;每一层有两个子层&#xff0c;第一个子层包含多头注意力机制&#xff0c;第二个子层是前…

Spring MVC相关注解运用 —— 中篇

目录 一、RESTful风格支持 1.1 RESTful风格介绍 1.2 postman使用 二、PathVariable 2.1 实例程序 2.2 测试结果 三、PostMapping、GetMapping、PutMapping、DeleteMapping 四、HiddenHttpMethodFilter 4.1 在web.xml配置过滤器 4.2 控制器方法 4.3 JSP页面 4.4 测…

数据库管理工具DBeaver 连接 TDengine详细教程

数据库管理工具DBeaver 连接 TDengine 一、介绍二、前置条件2.1 TDEngine安装 2.2 DBeaver 下载及安装三、DBeaver 连接 TDengine 一、介绍 Dbeaver是一款功能强大的数据库管理工具&#xff0c;支持任何拥有 JDBC-Driver 的数据库。TDengine是一款由涛思数据开发的国产的时序数…

【网络编程】网络编程套接字(二)简单的UDP网络程序

文章目录 服务器编程1.创建服务端套接字2.绑定服务端套接字3.服务端启动 客户端编程1.创建客户端套接字2.绑定客户端套接字 服务器和客户端测试 服务器编程 1.创建服务端套接字 使用socket函数调用可以创建套接字的文件描述符&#xff0c;与前边的文件类似&#xff0c;socket…

【基础算法】递归算法

递归算法是一种直接或间接调用原算法的算法&#xff0c;一个使用函数自身给出定义的函数被称为递归函数。利用递归算法可以将规模庞大的问题拆分成规模较小的问题&#xff0c;从而使问题简化。无论是递归算法还是递归函数&#xff0c;最大的特点都是“自己调用自己”。 斐波那…

nRF52832蓝牙概述

基本概念 RSSI&#xff08;Received Signal Strength Indicator&#xff09;是接收信号的强度指示。 接收包RSSI是指无线模块发送信息后&#xff0c;接收端的无线模块接收到数据后&#xff0c;当前接收数据的信号强度的寄存器值&#xff0c;也就是接收模块获取到发送模块当前发…

Vector - CAPL - 数据库和CAPL_01

目录 获取CAN总线报文信息 静态访问报文信息 动态访问报文信息 静态访问数据库信息 DBLookup&#xff08;Access Message & Signal&#xff09; 1、报文类型信息 2、类型信息 3、节点信息 获取CAN总线报文信息 我们在做CAN网络管理或者通信的测试的过程中&#xf…

LLM prompt提示构造案例

参考&#xff1a; https://github.com/PlexPt/awesome-chatgpt-prompts-zh 吴恩达 prompt工程应用&#xff1a; https://www.bilibili.com/video/BV1No4y1t7Zn prompt构造案例代码 prompt """文本分类任务&#xff1a;将一段用户给外卖服务的评论进行分类…

LSTM已死,Transformer永生(面试问答RNN/LSTM/Transformer)

计算机视觉面试题-Transformer相关问题总结&#xff1a;https://zhuanlan.zhihu.com/p/554814230 计算机视觉面试31题 CV面试考点&#xff0c;精准详尽解析&#xff1a;https://zhuanlan.zhihu.com/p/257883797 1. 循环神经网络&#xff08;Recurrent Neural Networks, RNN&am…

渲染颜色透明度异常分析 Unity RenderTexture

解决 Unity Canvas 相机 RenderTarget 渲染颜色透明度异常的问题 问题 重现场景 新建一个 Canvas-RT , Canvas Render Mode 改为 Screen Space - Camera 。 为 Canvas-RT 添加一个 RawImage-Origin 对象&#xff0c;修改颜色透明度为 120 。 修改 Camera-RT 中的 Target Textur…

如何实现Nginx+Tomcat反向代理与负载均衡

目录 一、正向代理与反向代理 正向代理 反向代理 二、负载均衡 什么是负载均衡 代码仓库定义 分流策略 权重 least_conn&#xff08;最少连接&#xff09; ip_hash&#xff08;负载均衡模式&#xff09; fair&#xff08;第三方负载均衡模式&#xff09; url_hash&…

算法设计与分析 课程期末复习简记

目录 网络流 线性规划 回溯算法 分支限界 贪心算法 动态规划 分治算法 算法复杂度分析 相关概念 网络流 下面是本章需要掌握的知识 • 流量⽹络的相关概念 • 最⼤流的概念 • 最⼩割集合的概念 • Dinic有效算法的步骤 • 会⼿推⼀个流量⽹络的最⼤流 下面对此依次进行复…