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

论QT6多线程技术

前言

以前我多线程使用传统的继承qthread重写run()或者继承qrunable类把对象丢到线程池解决。经过昨天的面试让我了解到新的技术,我之前看到过只不过没有详细的去了解movetotread技术,这个技术是qt5推出的,qt6还在延续使用

代码结构

以下是简单的movetotread的实现

class Worker:public QObject{
Q_OBJECT
private slots:
dowork();/*业务逻辑*/
}//使用方式
QThread thread;
Worker woker;
woker.movetotread(&tread);
thread.start();
//通过信号触发work
QObject::connect(&sender,&sender::startsignal,&worker,&worker::doworke);

实现逻辑

movetotread实现了线程与事务相分离,但需要运行某个事件的时候只需要将继承了QObject类的对象通过movetotread(&目标线程)传进去执行,通过qdequeueconnect()实现跨线程通讯。

关键操作

初次创建线程的时候通过start()函数,它会调用run()函数并启动事件循环(默认exec())

退出线程有三种

thread->quit();//优雅退出
tread->wait();//主线程阻塞等待子线程结束
thread->terminate();//强制退出线程,不推荐这种,可能导致线程未释放

创建好线程以后可以写两个connect管理对象和线程当线程执行完时释放finished信号来管理对象和线程的生命周期

connect(thread,&qthread::finished,worker,&QObject::deletelater);
connect(thread,&qthread::finished,thread,&QObject::deletelater);

跨线程的时候不要直接调用对象内的方法,可以通过主线程connect信号触发worker->doworker();

其他注意细节

如果线程未被释放,是可以通过movetothread将新的对象传进去。

如果向一个线程里面重复movetothread,最新的对象会把上一个对象给替代掉。

小实验

我设计两个线程,一个是主线程,里面是mainwindow,一个是子线程,专门生产1-6的随机数,生产好了以后将生成的数字传递到主线程显示出来

首先是建一个随机数生成器类randomnum

//头文件
#ifndef RANDOMNUM_H
#define RANDOMNUM_H
#include<QObject>
#include<QRandomGenerator>
#include<QTimer>class randomnum : public QObject
{Q_OBJECT
public:explicit randomnum(QObject *parent = nullptr);
public slots:void startrandom();//开始生成随机数void stoprandom();//暂停生成
signals:void newnumber(int count,int number);
private:QTimer *timer;//计时器int count=0;//计数QRandomGenerator random;//随机数生成器
};#endif // RANDOMNUM_H
//cpp
#include "randomnum.h"
#include "qobject.h"randomnum::randomnum(QObject *parent): QObject{parent}
{timer=new QTimer(this);connect(timer,&QTimer::timeout,this,[this](){count++;int num=random.bounded(1,6);emit newnumber(count,num);});
}void randomnum::startrandom()
{timer->start(1000);
}void randomnum::stoprandom()
{timer->stop();
}

主程序

//头文件
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:Ui::MainWindow *ui;QThread *thread1;private slots:void appendnum(int count,int num);};
#endif // MAINWINDOW_H
//cpp文件
#include "randomnum.h"
#include "ui_mainwindow.h"
#include<QString>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);ui->plainTextEdit->setReadOnly(true);//创建工作对象和线程randomnum *random1=new randomnum;thread1=new QThread(this);//把工作对象移动到子线程random1->moveToThread(thread1);//连接信号槽//触发开始随机数的信号//connect(thread1,&QThread::started,random1,&randomnum::startrandom);//把子线程生成的信号参数传给主线程对应的槽函数connect(random1,&randomnum::newnumber,this,&MainWindow::appendnum);//开始按钮connect(ui->btnstart,&QPushButton::clicked,random1,&randomnum::startrandom);//暂停按钮connect(ui->btnstop,&QPushButton::clicked,random1,&randomnum::stoprandom);//管理对象生命周期connect(thread1,&QThread::finished,random1,&QObject::deleteLater);//connect(thread1,&QThread::finished,thread1,&QObject::deleteLater);thread1->start();
}MainWindow::~MainWindow()
{if(thread1&&thread1->isRunning()){thread1->quit();thread1->wait();}delete ui;
}void MainWindow::appendnum(int count, int num)
{QString str=QString("第%1次,数字是%2").arg(count).arg(num);ui->plainTextEdit->appendPlainText(str);
}

显示效果

程序怎么实现的看上面代码就行了,这里讲下遇到的问题:

1.关闭程序,程序崩溃,子线程没有停止导致的,刚开始的时候明明有一个connect连接finished的信号,结果还是没关掉,原因是deletlater只是标记了他为待删除,不需要这一句,直接在析构函数里面显示删除,之前那一句不要了,避免重复删除

2.添加开始/停止按钮,用这个直接操作计时器,不是操控线程就可以实现 

http://www.xdnf.cn/news/6598.html

相关文章:

  • linux-配置定时任务
  • 一道canvas算法题(看过记录下)
  • js在浏览器执行原理
  • 【Linux】Linux安装并配置mysql
  • vue基本介绍
  • H.264/AVC 变换量化编码核心技术拆解
  • C#语言中 (元,组) 的发展史
  • Unity基础学习(十五)核心系统——音效系统
  • PC:使用WinSCP密钥文件连接sftp服务器
  • c++作业整理2
  • 纯前端实现基于位置的天气和动态背景图片
  • 行为型模式:责任链模式
  • 代码随想录 算法训练 Day2:数组
  • 第七节第三部分:从JDK8开始接口新增的方法、接口的多继承、注意事项
  • 一.android Studio开发系统应用——导入TvSettings源码
  • Medical | 药品追溯码【待续】
  • 2025-5-15Vue3快速上手
  • 散热片为何“失效”?热阻路径建模的常见误区解析
  • 并发控制:确保多线程环境下的数据一致性与完整性
  • SymPy | 使用SymPy求解多元非线性方程组
  • 3DVR制作的工具或平台
  • windows ffmpeg msvc x64编译
  • keil uniFlash烧录出现八字节对齐错误
  • 并发编程(二)
  • ProfibusDP主站转ModbusRTU/TCP与横河AXG电磁流量计通讯案例
  • 语音识别——声纹识别
  • bfs搜索加标记连通区域id实现时间优化(空间换时间)
  • C++文件操作--1 文本文件操作
  • MYSQL之基本查询(CURD)
  • 基于javaweb的JSP+Servlet家政服务系统设计与实现(源码+文档+部署讲解)