Qt第十七章 多线程

文章目录

  • 多线程
    • 1. 线程概念的起源
    • 2. 三种方式创建线程
    • 3. 启动线程前的准备工作
    • 4. 启动线程/退出线程
    • 5. 操作运行中的线程
    • 6. 为每个线程提供独立数据
    • 7.子线程不能操作ui
      • 解决方案

多线程

1. 线程概念的起源

  • 单核CPU
    早期还没有线程的概念,如何保证2个进程同时进行呢?时间片轮转调度
    每次被CPU选中来执行当前进程所用的时间,时间一到,无论进程是否运行结束,操作系统都会强制将CPU这个资源转到另一个进程去执行。
  • 多核CPU
    随着运行的进程越来越多,人们发现进程的创建、撤销与切换存在着较大的时空开销,因此业界急需一种轻型的进程技术来减少开销。于是上世纪80年代出现了一种叫SMP的对称多处理技术,就是我们所知的线程概念。
    线程切换的开销要小很多,这是因为每个进程都有属于自己的一个完整虚拟地址空间,而线程隶属于某一个进程,与进程内的其他线程一起共享这片地址空间,基本上就可以利用进程所拥有的资源而无需调用新的资源,故对它的调度所付出的开销就会小很多。

2. 三种方式创建线程

  1. 线程入口函数
  • 全局函数
#include <QThread>
void helloThread()
{for (int i = 0; i < 99999999; ++i) {qDebug() << "hello";}
}int main(int argc, char* argv[])
{QApplication a(argc, argv);QThread* th1 = QThread::create(helloThread);th1->start();return a.exec();
}
void helloThread(QString s)
{for (int i = 0; i < 99999999; ++i) {qDebug() << "hello" << s;}
}int main(int argc, char* argv[])
{QApplication a(argc, argv);QThread* th1 = QThread::create(helloThread, "thread1");th1->start();return a.exec();
}
  • 静态成员函数
class A {
public:A() { }static void print(){for (int i = 0; i < 10; i++)qDebug() << __FUNCTION__;}
};int main(int argc, char* argv[])
{QApplication a(argc, argv);QThread* th1 = QThread::create(A::print);th1->start();return a.exec();
}
  • 成员函数
class A {
public:A() { }void print(){for (int i = 0; i < 10; i++)qDebug() << __FUNCTION__;}
};int main(int argc, char* argv[])
{QApplication a(argc, argv);A aFunc;QThread* th1 = QThread::create(&A::print, &aFunc);th1->start();return a.exec();
}
  • lamda表达式
    QThread* th2 = QThread::create([=] { qDebug() << "lamda"; });th2->start();
  • 连接信号与槽
    QObject::connect(th2, &QThread::started, [=] { qDebug() << "th2线程启动"; });QObject::connect(th1, &QThread::finished, [=] { qDebug() << "th1线程执行完毕";th1->deleteLater(); });
  1. 继承QThread重写run
class MyThread : public QThread {
public:void run() override{for (int i = 0; i < 10; i++) {qDebug() << "MyThread" << i;if (i == 5)quit(); // 只能在线程中调用,但是要等事件结束才结束}}
};
int main(int argc, char* argv[])
{QApplication a(argc, argv);MyThread th3;th3.start();th3.exit(); // 结束线程,也要等事件结束才结束    return a.exec();    
}
  1. QObject::moveToThread
class Download : public QObject {Q_OBJECT
public:Download(QObject* parent = nullptr): QObject(parent){}
public slots:void downloadFile(){for (int i = 0; i < 100; i++)qDebug() << "下载进度=====" << i << "%";emit finished();}
signals:void finished();
};class APP : public QObject {Q_OBJECT
public:APP(QObject* parent = nullptr): QObject(parent){d = new Download;th = new QThread;connect(this, &APP::startDownload, d, &Download::downloadFile);connect(d, &Download::finished, [=] { qDebug() << "下载完成"; });d->moveToThread(th);connect(th, &QThread::finished, th, &QThread::deleteLater);th->start();}
signals:void startDownload();private:Download* d;QThread* th;
};
int main(int argc, char* argv[])
{QApplication a(argc, argv);APP ap;emit ap.startDownload();return a.exec();
}#include "main.moc"

3. 启动线程前的准备工作

    // 建议最多同时开多少线程数qDebug() << QThread::idealThreadCount();// 改变栈空间,如果线程运行所占空间很大,那就会崩溃,需要改变qDebug() << "原始栈空间" << th3.stackSize(); // 原始栈空间 0th3.setStackSize(1024 * 1024 * 3);qDebug() << "现在栈空间" << th3.stackSize();//现在栈空间 3145728

4. 启动线程/退出线程

  • 启动线程

调用start()函数后,新线程会优先执行run()中的代码,再执行其他的
默认run()会调用exec()函数,即启动一个局部的不占CPU的事件循环

5. 操作运行中的线程

  • 休眠函数
void helloThread(QString s)
{for (int i = 0; i < 9; ++i) {qDebug() << "hello" << s;QThread::sleep(1); // 睡眠1秒QThread::msleep(100); // 睡眠100毫秒QThread::usleep(1000); // 睡眠1000微秒}
}
  • 中断标志
class MyThread : public QThread {
public:void run() override{for (int i = 0; i < 10; i++) {qDebug() << "MyThread" << i;// 中断标志if (this->isInterruptionRequested())break;// 请求中断if (i == 3)this->requestInterruption();}}
};

在这里插入图片描述

6. 为每个线程提供独立数据

关于全局变量,在2个线程里修改会相互影响

int g_num = 5;
void fun()
{g_num = 8;qInfo() << "g_num" << g_num;
}
void fun1()
{g_num = 9;qInfo() << "1_g_num" << g_num;
}
int main(int argc, char* argv[])
{QApplication a(argc, argv);QThread* th = QThread::create(fun);QThread* th1 = QThread::create(fun1);th->start();th1->start();return a.exec();
}

在这里插入图片描述
可以通过QThreadStorage类把全局变量设置成线程独立的变量

QThreadStorage<int> g_num;
void fun()
{g_num.setLocalData(8);qInfo() << "g_num" << g_num.localData();
}
void fun1()
{g_num.setLocalData(9);qInfo() << "1_g_num" << g_num.localData();
}
int main(int argc, char* argv[])
{QApplication a(argc, argv);QThread* th = QThread::create(fun);QThread* th1 = QThread::create(fun1);th->start();th1->start();qDebug() << "main_g_num" << g_num.localData();    return a.exec();
}

在这里插入图片描述

7.子线程不能操作ui

Gui框架一般只允许ui线程操作界面组件,Qt也是如此,否则会出现崩溃

解决方案

  • 通过信号与槽
    参考之前的moveToThread

  • 通过QMetaObject::invokeMethod

#include "Widget.h"
#include "./ui_Widget.h"
#include <QMetaObject>
#include <QThread>Widget::Widget(QWidget* parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QThread* th = QThread::create(&Widget::fun, this);th->start();
}Widget::~Widget()
{delete ui;
}void Widget::fun()
{QThread::sleep(5);QMetaObject::invokeMethod(ui->label, "setText", Q_ARG(QString, "hello"));
}void Widget::on_pushButton_clicked()
{fun();
}
  • 通过QApplication::postEvent
#include "Widget.h"
#include "./ui_Widget.h"
#include <QCoreApplication>
#include <QMetaObject>
#include <QThread>class MyEvent : public QEvent {
public:MyEvent(): QEvent(QEvent::Type(QEvent::User)){}
};Widget::Widget(QWidget* parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
}Widget::~Widget()
{delete ui;
}void Widget::fun()
{QCoreApplication::postEvent(this, new MyEvent);
}void Widget::customEvent(QEvent* ev)
{if (ev->type() == QEvent::User)this->move(-10, 0);
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Java爬取微博数据(四) 获取 图片 or 视频

基于Java爬取微博数据四 获取 图片 or 视频 图片 or 视频转存 图片 or 视频注意点 前面已经讲述了基于 Java 爬取微博正文列表内容&#xff0c;微博用户主页内容以及导出爬取到的微博数据等操作&#xff0c;那么下面讲述一下如何处理微博正文中的图片/视频等内容。 图片 or 视…

(转载)使用zed相机录制视频

参照下面这个链接 https://blog.csdn.net/peng_258/article/details/127457199?ops_request_misc&request_id&biz_id102&utm_termzed2%E5%BD%95%E5%88%B6%E6%95%B0%E6%8D%AE%E9%9B%86&utm_mediumdistribute.pc_search_result.none-task-blog-2~all~sobaiduweb…

代码复现改进

代码复现&#xff0c;文献复现&#xff0c;文章复现&#xff0c; 算法复现&#xff0c;科研复现 Matlab,Python中英文均可 保证质量&#xff0c;加快你的研究速度 代码改进跑通&#xff0c;模型优化改进

三种相机模型总结(针孔、鱼眼、全景)

相机标定 文章目录 相机标定前言 前言 我们最常见的投影模型Perspective Projection Model描述的就是针孔相机的成像原理。从上面的图根据相似三角形可以得出 参考链接 https://zhuanlan.zhihu.com/p/540969207 相机标定之张正友标定法数学原理详解&#xff08;含python源码&a…

鹭鹰优化算法SBOA优化RBF神经网络的扩散速度实现多数入多输出数据预测,可以更改数据集(MATLAB代码)

一、鹭鹰优化算法介绍 鹭鹰优化算法&#xff08;Secretary Bird Optimization Algorithm, SBOA&#xff09;是一种新型的元启发式算法&#xff0c;它于2024年4月由Youfa Fu等人提出&#xff0c;并发表在SCI人工智能二区顶刊《Artificial Intelligence Review》上。该算法的灵感…

uniapp h5手机如何打开本地跑的前端项目进行本地调试

本地调试使用 vConsole是一个轻量级的移动端调试工具&#xff0c;可以在iOS设备上直接调试Uniapp H5应用。下面是具体的步骤&#xff1a; 在Uniapp项目中安装vConsole依赖&#xff1a;npm install vconsole。 在项目的main.js文件中引入vConsole库&#xff1a;import VConso…

将iso格式的镜像文件转化成云平台能安装的镜像格式(raw/vhd/QCOW2/VMDK )亲测--图文详解

1.首先,你将你的iso的文件按照正常的流程和需求安装到你的虚拟机中,我这里使用的是vmware,安装完成之后,关机。再次点开你安装好的那台虚拟机的窗口,如下图 选中要导出的镜像,镜像需要关机 2.点击工具栏的文件------选择 导出 整个工程到 ovf 格式—这里你可以选择你要导…

思科设备静态路由实验

拓扑及需求 网络拓扑及 IP 编址如图所示&#xff1b;PC1 及 PC2 使用路由器模拟&#xff1b;在 R1、R2、R3 上配置静态路由&#xff0c;保证全网可达&#xff1b;在 R1、R3 上删掉上一步配置的静态路由&#xff0c;改用默认路由&#xff0c;仍然要求全网可达。 各设备具体配置…

【数模修炼之旅】05 拟合模型 深度解析(教程+代码)

【数模修炼之旅】05 拟合模型 深度解析&#xff08;教程代码&#xff09; 接下来 C君将会用至少30个小节来为大家深度解析数模领域常用的算法&#xff0c;大家可以关注这个专栏&#xff0c;持续学习哦&#xff0c;对于大家的能力提高会有极大的帮助。 1 拟合模型介绍及应用 …

C++ | Leetcode C++题解之第357题统计各位数字都不同的数字个数

题目&#xff1a; 题解&#xff1a; class Solution { public:int countNumbersWithUniqueDigits(int n) {if (n 0) {return 1;}if (n 1) {return 10;}int ans 10, cur 9;for (int i 0; i < n - 1; i) {cur * 9 - i;ans cur;}return ans;} };

91.WEB渗透测试-信息收集-Google语法(5)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;90.WEB渗透测试-信息收集-Google语法&#xff08;4&#xff09; 怎样判断哪些漏洞有什么样…

数据结构——顺序栈和链式栈

目录 引言 栈的定义 栈的分类 栈的功能 栈的声明 1.顺序栈 2.链式栈 栈的功能实现 1.栈的初始化 (1)顺序栈 (2)链式栈 (3)复杂度分析 2.判断栈是否为空 (1)顺序栈 (2)链式栈 (3)复杂度分析 3.返回栈顶元素 (1)顺序栈 (2)链式栈 (3)复杂度分析 4.返回栈的大…

怎么管控终端电脑上的移动端口

管控终端电脑上的移动端口&#xff0c;尤其是USB等移动端口&#xff0c;是确保企业数据安全和提升网络管理效率的重要手段。 一、使用注册表编辑器禁用USB端口&#xff08;适用于Windows系统&#xff09; 打开注册表编辑器&#xff1a; 同时按下“WinR”组合键&#xff0c;打…

IPD产品开发流程详细活动图及说明

1、概念阶段 完整见文章后 2、计划阶段 篇幅有限&#xff0c;获取完整阶段活动图以及步骤说明&#xff0c;见下图

【UE5】Groom毛发系统的基本使用——给小白人添加头发

目录 效果 步骤 一、准备 二、使用3DsMax制作毛发 三、在UE中给小白人安装毛发 四、修改毛发材质 效果 步骤 一、准备 1. 新建一个第三人称模板工程 2. 在项目设置中&#xff0c;勾选“支持计算蒙皮缓存” 3. 在插件面板中&#xff0c;启用“Groom”和“Alembic Gro…

API网关之Apache ShenYu

Apache ShenYu&#xff08;原名Soul&#xff09;是一个开源的API网关&#xff0c;旨在支持高性能、跨语言和云原生架构。它为管理和控制客户端与服务之间的数据流提供了一种高效且可扩展的解决方案。 文档见 Apache ShenYu 介绍 | Apache ShenYu 以下是Apache ShenYu的详细介…

Open3D mesh 模型锐化

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 输入参数 输出参数 2.2完整代码 三、实现效果 3.1原始mesh 3.2处理后mesh 3.3数据显示 Open3D点云算法汇总及实战案例汇总的目录地址&#xff1a; Open3D点云算法与点云深度学习案例汇总…

【大模拟】逻辑回环类

区块链 AcWing 3285. 区块链 - AcWing 区块链涉及密码学、哈希算法、拜占庭问题、共识算法、故障模型、网络模型等诸多知识&#xff0c;也在金融等领域有广泛的应用。 本题中&#xff0c;我们需要实现一个简单的区块链系统。 在一个分布式网络中&#xff0c;有 nn 个节点通…

5G毫米波测试助力突破高频段设备局限,实现高效外场测试

作者介绍 一、方案背景 随着业务对带宽需求的不断增加&#xff0c;通信频谱不断向更高频谱延伸&#xff0c;5G毫米波具有丰富的频率资源&#xff0c;是移动通信技术演进的必然方向。下图是ITU的WRC-19会议发布的目前5G所占用频段。 从图中可以看出&#xff0c;在5G毫米波测试中…

Java基础核心知识学习笔记

方法重载 请记住下面重载的条件 方法名称必须相同。参数列表必须不同&#xff08;个数不同、或类型不同、参数类型排列顺序不同等&#xff09;。方法的返回类型可以相同也可以不相同。仅仅返回类型不同不足以成为方法的重载。重载是发生在编译时的&#xff0c;因为编译器可以根…