C++ Qt 学习(七):Qt 线程与并发
1. Qt 创建线程的三种方法
1.1 方式一:派生于 QThread
-
派生于 QThread,这是 Qt 创建线程最常用的方法,重写虚函数 void QThread::run(),在 run() 写具体的内容,外部通过 start 调用,即可执行线程体 run()
- 派生于 QThread 的类,构造函数属于主线程,run() 函数属于子线程,可以通过打印线程 id 判断
-
main.cpp
#include <QCoreApplication>
#include <iostream>
#include "thread01.h"int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);std::cout << "main thread " << QThread::currentThreadId() << std::endl;Thread01 *th = new Thread01();th->start();std::cout << "main thread end" << std::endl;return a.exec();
}
- thread01.h
#pragma once
#include <QThread>class Thread01 : public QThread {Q_OBJECTpublic:Thread01();void run() override;
};
- thread01.cpp
#include "thread01.h"
#include <QDebug>Thread01::Thread01() {qDebug() << "Thread01 construct " << QThread::currentThreadId();
}void Thread01::run() {qDebug() << "Thread01 run " << QThread::currentThreadId();int index = 0;while (1) {qDebug() << index++;QThread::msleep(500);}
}
- 控制台输出
main thread 00004A20
Thread01 construct 0x4a20 // 构造函数属于主线程
Thread01 run 0x4f18 // run() 函数属于子线程
0
main thread end
1
2
3
...
1.2 方式二:派生于 QRunnable
-
派生于 QRunnable,重写 run() 方法,在 run() 方法里处理其它任务,调用时需要借助 Qt 线程池
- 这种新建线程的方法的缺点是:不能使用 Qt 的信号与槽机制,因为 QRunnable 不是继承自 QObject
- 但这种方法的好处是:可以让 QThreadPool 来管理线程,QThreadPool 会自动清理新建的 QRunnable 对象
-
main.cpp
#include <QCoreApplication>
#include <iostream>
#include "thread02.h"
#include <QThreadPool>int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);std::cout << "main thread" << QThread::currentThreadId() << std::endl;Thread02 *th = new Thread02();QThreadPool::globalInstance()->start(th);std::cout << "main thread end" << std::endl;return a.exec();
}
- thread02.h
#pragma once
#include <QRunnable>class Thread02 : public QRunnable {
public:Thread02();~Thread02();void run() override;
};
- thread02.cpp
#include "thread02.h"
#include <QThread>
#include <QDebug>Thread02::Thread02() {qDebug() << "Thread02 construct " << QThread::currentThreadId();
}Thread02::~Thread02() {qDebug() << "Thread02 xigou func";
}void Thread02::run() {qDebug() << "Thread02 run " << QThread::currentThreadId();
}
1.3 moveToThread
-
派生于 QObject,使用 moveToThread 方法
- 将 QThread 对象作为私有成员,在构造函数里 moveToThread,然后启动线程
-
ch71_moveToThread.h
#pragma once#include <QtWidgets/QWidget>
#include "ui_ch71_moveToThread.h"
#include "Thread03.h"class ch71_moveToThread : public QWidget {Q_OBJECTpublic:ch71_moveToThread(QWidget *parent = nullptr);~ch71_moveToThread();private slots:void on_pushButton_clicked();signals:void sig_fun();private:Ui::ch71_moveToThreadClass ui;Thread03* m_pTh03 = nullptr;
};
- ch71_moveToThread.cpp
#include "ch71_moveToThread.h"
#include <QDebug>ch71_moveToThread::ch71_moveToThread(QWidget *parent) : QWidget(parent) {ui.setupUi(this);qDebug() << "main construct " << QThread::currentThreadId();m_pTh03 = new Thread03();connect(this, &ch71_moveToThread::sig_fun, m_pTh03, &Thread03::fun);
}ch71_moveToThread::~ch71_moveToThread() {}void ch71_moveToThread::on_pushButton_clicked() {emit sig_fun();
}
- Thread03.h
#pragma once
#include <QObject>
#include <QThread>class Thread03 : public QObject {
public:Thread03();public slots:void fun();private:QThread m_th;
};
- Thread03.cpp
#include "Thread03.h"
#include <QDebug>Thread03::Thread03() {this->moveToThread(&m_th);m_th.start();qDebug() << "Thread03 construct " << QThread::currentThreadId();
}void Thread03::fun() {qDebug() << "Thread03 fun " << QThread::currentThreadId();int index = 0;while (1) {qDebug() << index++;QThread::msleep(300);}
}
- 控制台输出
main construct 0x11f0
Thread03 construct 0x11f0
// 点击按钮后
Thread03 fun 0x2b74
0
1
2
3
...
2. Qt 并发
2.1 QtConcurrent 基本用法
- ch72_concurrent.h
#pragma once#include <QtWidgets/QWidget>
#include "ui_ch72_concurrent.h"class ch72_concurrent : public QWidget {Q_OBJECTpublic:ch72_concurrent(QWidget *parent = nullptr);~ch72_concurrent();int timeTask();private slots:void on_pushButton_clicked();private:Ui::ch72_concurrentClass ui;
};
- ch72_concurrent.cpp
#include "ch72_concurrent.h"
#include <QThread>
#include <QDebug>
#include <QtConcurrent>
#include <QFuture>ch72_concurrent::ch72_concurrent(QWidget *parent) : QWidget(parent) {ui.setupUi(this);
}ch72_concurrent::~ch72_concurrent() {}int ch72_concurrent::timeTask() {int num = 0;for (int i = 0; i < 1000000; i++) {num++;qDebug() << num;}return num;
}void ch72_concurrent::on_pushButton_clicked() {//timeTask();QFuture<int> ft = QtConcurrent::run(this, &ch72_concurrent::timeTask);while (!ft.isFinished()) {// 当 future 未完成时,让 cpu 去做别的事情QApplication::processEvents(QEventLoop::AllEvents, 30);}
}
2.2 QtConcurrent run() 参数说明
- QtConcurrent::run 函数参数,可以是全局函数,也可以是类成员函数
- ch73_concurrent.cpp
#include "ch73_concurrent.h"
#include <QDebug>
#include <QtConcurrent>
#include <QFuture>ch73_concurrent::ch73_concurrent(QWidget *parent) : QWidget(parent) {ui.setupUi(this);
}ch73_concurrent::~ch73_concurrent() {}int ch73_concurrent::timeTask(int num1, int num2) {//int num = 0;for (int i = 0; i < 1000000; i++) {num1++;num2++;qDebug() << num1;qDebug() << num2;}return num1 + num2;
}int gTimeTask(int num1, int num2) {//int num = 0;for (int i = 0; i < 1000000; i++) {num1++;num2++;qDebug() << num1;qDebug() << num2;}return num1 + num2;
}void ch73_concurrent::on_pushButton_clicked() {//timeTask();int num1 = 0;int num2 = 0;//QFuture<int> ft = QtConcurrent::run(this, &ch73_concurrent::timeTask, num1, num2);QFuture<int> ft = QtConcurrent::run(gTimeTask, num1, num2);while (!ft.isFinished()) {QApplication::processEvents(QEventLoop::AllEvents, 30);}
}
2.3 获取 QtConcurrent 的返回值
- 获取 QtConcurrent 的结果,需要使用 QFutureWatcher 类,链接它的信号 finished,然后给 watcher 设置 future,当监控到 future 执行结束后,可以获取它的执行结果,调用的是 result() 函数
- ch74.cpp
#include "ch74.h"
#include <QDebug>
#include <QtConcurrent>
#include <QFuture>
#include <QFutureWatcher>ch74::ch74(QWidget *parent) : QWidget(parent) {ui.setupUi(this);
}ch74::~ch74() {}int ch74::timeTask(int& num1, int& num2) {for (int i = 0; i < 1000; i++) {num1++;num2++;qDebug() << num1;qDebug() << num2;}return num1 + num2;
}void ch74::on_pushButton_clicked() {int num1 = 0;int num2 = 0;QFutureWatcher<int>* fw = new QFutureWatcher<int>;connect(fw, &QFutureWatcher<int>::finished, [&]{qDebug() << "QFutureWatcher finished";qDebug() << "result = " << fw->result();});QFuture<int> ft = QtConcurrent::run(this, &ch74::timeTask, num1, num2);fw->setFuture(ft);while (!ft.isFinished()) {QApplication::processEvents(QEventLoop::AllEvents, 30);}
}
3. C++ 其他线程技术
- pthread:linux 线程
- win32-pthread, obs 的线程全部使用了 win32-pthread
- windows thread 类
- MFC thread类
- boost
- std::thread(推荐用这个,基于语言级别的跨平台 C++ 线程)
相关文章:

C++ Qt 学习(七):Qt 线程与并发
1. Qt 创建线程的三种方法 1.1 方式一:派生于 QThread 派生于 QThread,这是 Qt 创建线程最常用的方法,重写虚函数 void QThread::run(),在 run() 写具体的内容,外部通过 start 调用,即可执行线程体 run() …...

Django框架之模板层
【一】Django模板系统 官方文档:官方文档 【二】常用语法 只需要记两种特殊符号: {{ }}和 {% %} 变量相关的用{逻辑相关的用{%%}。 【三】变量 在Django的模板语言中按此语法使用: {{ 变量名 }}。 当模版引擎遇到一个变量,它…...

【AI视野·今日Robot 机器人论文速览 第六十五期】Mon, 30 Oct 2023
AI视野今日CS.Robotics 机器人学论文速览 Mon, 30 Oct 2023 Totally 18 papers 👉上期速览✈更多精彩请移步主页 Daily Robotics Papers Gen2Sim: Scaling up Robot Learning in Simulation with Generative Models Authors Pushkal Katara, Zhou Xian, Katerina F…...

LuatOS-SOC接口文档(air780E)--otp - OTP操作库
otp.read(zone, offset, len)# 读取指定OTP区域读取数据 参数 传入值类型 解释 int 区域, 通常为0/1/2/3, 与具体硬件相关 int 偏移量 int 读取长度, 单位字节, 必须是4的倍数, 不能超过4096字节 返回值 返回值类型 解释 string 成功返回字符串, 否则返回nil 例…...

为什么LDO一般不用在大电流场景?
首先了解一下LDO是什么? LDO(low dropout regulator,低压差线性稳压器)或者低压降稳压器,它的典型特性就是压降。 那么什么是压降? 压降电压 VDO 是指为实现正常稳压,输入电压 VIN 必须高出 所…...

Adobe家里的“3D“建模工 | Dimension
今天,我们来谈谈一款在Adobe系列中比肩C4D的高级3D软件的存在—— Dimension。 Adobe Dimension ,其定位是一款与Photoshop以及Illustrator相搭配的3D绘图软件。 Adobe Dimensions与一般的3D绘图软件相较之下,在操作界面在功能上有点不大相同…...

MIB 6.1810实验Xv6 and Unix utilities(2)sleep
难度:easy Implement a user-level sleep program for xv6, along the lines of the UNIX sleep command. Your sleep should pause for a user-specified number of ticks. A tick is a notion of time defined by the xv6 kernel, namely the time between two interrupts f…...

修改 jar 包中的源码方式
在我们开发的过程中,我们有时候想要修改jar中的代码,方便我们调试或或者作为生产代码打包上线,但是在IDEA中,jar包中的文件都是read-only(只读模式)。那如何我们才能去修改jar包中的源码呢? 1.…...

Linux命令--重启系统的方法
原文网址:Linux命令--重启系统的方法_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Linux重启系统的方法。 普通重启 reboot reboot的工作过程跟下边的halt差不多,不过它是引发主机重启,而halt是关机。它的参数与halt相差不多。 shutdown …...

操作系统 day10(调度的概念、层次、七状态模型)
调度的概念 调度的层次 作业调度(高级调度) 进程调度(低级调度) 内存调度(中级调度) 挂起态与七状态模型 三层调度的联系和对比...

MIB 6.1810操作系统实验:准备工作(Tools Used in 6.1810)
6.1810 / Fall 2023 实验环境: Ubuntuxv6实验必要的依赖环境能通过make qemu进入系统 $ sudo apt-get update && sudo apt-get upgrade $ sudo apt-get install git build-essential gdb-multiarch qemu-system-misc gcc-riscv64-linux-gnu binutils-ri…...

快速弄懂C++中的深拷贝和浅拷贝
浅拷贝 浅拷贝就是单纯拷贝指向该对象的内存,所以在进行多次浅拷贝后只是相当于多了几个指向同一个对象的指针,而深拷贝相当于完全复制了一个对象副本。浅拷贝指的是复制对象的所有成员变量的值,不管这些值是指针、基本数据类型还是其他对象…...

AWD比赛中的一些防护思路技巧
## 思路1: 1、改服务器密码 (1)linux:passwd (2)如果是root删除可登录用户:cat /etc/passwd | grep bash userdel -r 用户名 (3)mysql:update mysql.user set…...

【C++面向对象】14. 命名空间
文章目录 【 1. 命名空间的定义 】【 2. using 指令 】2.1 using 指定命名空间的全部2.2 using 指定命名空间的部分 【 3. 不连续的命名空间 】【 4. 嵌套的命名空间 】 问题的背景:假设这样一种情况,当一个班上有两个名叫 Zara 的学生时,为了…...

asp.net实验管理系统VS开发sqlserver数据库web结构c#编程web网页设计
一、源码特点 asp.net 实验管理系统 是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使用c#语言开发。 asp.net实验管理系统1 应用技术&am…...

基于SSM+Vue的健身房管理系统
基于SSMVue的健身房管理系统的设计与实现~ 开发语言:Java数据库:MySQL技术:SpringMyBatisSpringMVC工具:IDEA/Ecilpse、Navicat、Maven 系统展示 主页 课程信息 健身器材 管理员界面 用户界面 摘要 健身房管理系统是一种利用现…...

《C++避坑神器·二十三》C++异常处理exception
有些时候无法设置弹出提示信息或者发送提示信息,时候可以抛出异常来提示各种情况 定义自己的异常 GetPostion()函数内部抛出了异常,所以在捕获异常的时候try要把这个函数包住, Catch()里面写throw后面的类,然后catch内部通过调…...

安卓播放解码后的byte字节视频
参考文章:安卓播放解码后的byte字节视频 - 简书 wlmedia播放器集成(4)— 实现视频播放 一个很棒的库, github地址:https://github.com/wanliyang1990/wlmedia About Android 音视频播放SDK,几句代码即可实…...

ceph 14.2.10 aarch64 非集群内 客户端 挂载块设备
集群上的机器测试 706 ceph pool create block-pool 64 64 707 ceph osd pool create block-pool 64 64 708 ceph osd pool application enable block-pool rbd 709 rbd create vdisk1 --size 4G --pool block-pool --image-format 2 --image-feature layering 7…...

21、Flink 的table API与DataStream API 集成(2)- 批处理模式和inser-only流处理
Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…...

051-第三代软件开发-日志容量时间限制
第三代软件开发-日志容量时间限制 文章目录 第三代软件开发-日志容量时间限制项目介绍日志容量时间限制 关键字: Qt、 Qml、 Time、 容量、 大小 项目介绍 欢迎来到我们的 QML & C 项目!这个项目结合了 QML(Qt Meta-Object Language…...

9步打造个人ip
什么是个人IP? 就是一个人创造出来的属于自己的有个性有价值的,能让他人记住你,信任你,认可你的东西。 如何强化个人IP呢? 需要一些必要的条件如专业性、耐心、勤奋等等要知道,打造IP是一个见效慢的过程&am…...

【深度学习】吴恩达课程笔记(四)——优化算法
笔记为自我总结整理的学习笔记,若有错误欢迎指出哟~ 【吴恩达课程笔记专栏】 【深度学习】吴恩达课程笔记(一)——深度学习概论、神经网络基础 【深度学习】吴恩达课程笔记(二)——浅层神经网络、深层神经网络 【深度学习】吴恩达课程笔记(三)——参数VS超参数、深度…...

MyBatis-plus 代码生成器配置
数据库配置(DataSourceConfig) 基础配置 属性说明示例urljdbc 路径jdbc:mysql://127.0.0.1:3306/mybatis-plususername数据库账号rootpassword数据库密码123456 new DataSourceConfig.Builder("jdbc:mysql://127.0.0.1:3306/mybatis-plus","root","…...

框架设计的核心要素
我们的框架应该给用户提供哪些构建产物?产物的模块格式如何?当用户没有以预期的方式使用框架时,是否应该打印合适的警告信息从而提供更好的开发体验,让用户快速定位问题?开发版本的构建和生产版本的构建有何区别&#…...

LeetCode - 26. 删除有序数组中的重复项 (C语言,快慢指针,配图)
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 思路一:快慢指针 在数组中,快慢指针就是两个整数下标,定义 fast 和 slow 这里我们从下标1开始(下标0的数据就1个,没有重复项)&…...

C#不安全代码
在C#中,“不安全代码”(unsafe code)通常指的是那些直接操作内存地址的代码。它允许开发者使用指针等低级别的数据结构,这些在通常的安全代码(safe code)中是不允许的。C# 的不安全代码提供了一种方式&…...

《C++避坑神器·二十二》VS能正常运行程序,但运行exe程序无响应解决办法
原因是某个文件只是放在了项目路径下,没有放在exe路径下,比如Json文件原来只放在了mlx项目下,导致VS可以运行,但运行exe无响应或报错如下: 两种方式修改: 1、把Json文件拷贝一份放到exe路径下 2、利用生成…...

lua调用C/C++的函数,十分钟快速掌握
系列文章目录 lua调用C\C动态库函数 系列文章目录摘要环境使用步骤你需要有个lua环境引入库码代码lua代码 摘要 在现代软件开发中,Lua作为一种轻量级脚本语言,在游戏开发、嵌入式系统等领域广泛应用。Lua与C/C的高度集成使得开发者能够借助其灵活性和高…...

自定义GPT已经出现,并将影响人工智能的一切,做好被挑战的准备了吗?
原创 | 文 BFT机器人 OpenAI凭借最新突破:定制GPT站在创新的最前沿。预示着个性化数字协助的新时代到来,ChatGPT以前所未有的精度来满足个人需求和专业需求。 从本质上讲,自定义GPT是之前的ChatGPT的高度专业化版本或代理,但自定…...