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…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...
0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化
是不是受够了安装了oracle database之后sqlplus的简陋,无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话,配置.bahs_profile后也能解决上下翻页这些,但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可,…...

在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例
目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码:冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...

医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor
1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...

2025-05-08-deepseek本地化部署
title: 2025-05-08-deepseek 本地化部署 tags: 深度学习 程序开发 2025-05-08-deepseek 本地化部署 参考博客 本地部署 DeepSeek:小白也能轻松搞定! 如何给本地部署的 DeepSeek 投喂数据,让他更懂你 [实验目的]:理解系统架构与原…...
深入解析 ReentrantLock:原理、公平锁与非公平锁的较量
ReentrantLock 是 Java 中 java.util.concurrent.locks 包下的一个重要类,用于实现线程同步,支持可重入性,并且可以选择公平锁或非公平锁的实现方式。下面将详细介绍 ReentrantLock 的实现原理以及公平锁和非公平锁的区别。 ReentrantLock 实现原理 基本架构 ReentrantLo…...