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…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...
Netty自定义协议解析
目录 自定义协议设计 实现消息解码器 实现消息编码器 自定义消息对象 配置ChannelPipeline Netty提供了强大的编解码器抽象基类,这些基类能够帮助开发者快速实现自定义协议的解析。 自定义协议设计 在实现自定义协议解析之前,需要明确协议的具体格式。例如,一个简单的…...
qt 双缓冲案例对比
双缓冲 1.双缓冲原理 单缓冲:在paintEvent中直接绘制到屏幕,绘制过程被用户看到 双缓冲:先在redrawBuffer绘制到缓冲区,然后一次性显示完整结果 代码结构 单缓冲:所有绘制逻辑在paintEvent中 双缓冲:绘制…...
MySQL用户远程访问权限设置
mysql相关指令 一. MySQL给用户添加远程访问权限1. 创建或者修改用户权限方法一:创建用户并授予远程访问权限方法二:修改现有用户的访问限制方法三:授予特定数据库的特定权限 2. 修改 MySQL 配置文件3. 安全最佳实践4. 测试远程连接5. 撤销权…...
Unity基础-Mathf相关
Unity基础-Mathf相关 一、Mathf数学工具 概述 Mathf是Unity中封装好用于数学计算的工具结构体,提供了丰富的数学计算方法,特别适用于游戏开发场景。它是Unity开发中最常用的数学工具之一,能够帮助我们处理各种数学计算和插值运算。 Mathf…...
大语言模型解析
1. Input Embedding embedding:将自然语言翻译成index 每个index对应一个embedding,embedding需要训练,embedding是一个数组...
vb监测Excel两个单元格变化,达到阈值响铃
需求 在Excel中实现监控两个单元格之间的变化范围,当达到某个设定的值的范围内时,实现自动响铃提示。 实现: 首先设置Excel,开启宏、打开开发者工具,点击visual Basic按钮,然后在左侧双击需要监测的shee…...
