Qt中如果槽函数运行时间久,避免阻塞主线程的做法
Qt中如果槽函数运行时间久,避免阻塞主线程的做法
一、解决步骤
- 创建一个工作线程类:继承自
QObject,并在其中实现槽函数的逻辑。 - 将工作线程类的实例移动到单独的线程中:通过
moveToThread()方法将对象移动到新线程。 - 启动线程:通过
QThread::start()启动线程。 - 连接信号和槽:使用
Qt::QueuedConnection连接信号和槽,确保槽函数在工作线程中异步执行。
二、示例代码
假设我们有一个耗时的槽函数longRunningTask(),需要将其放入单独的线程中执行。
1. 定义工作线程类
#include <QObject>
#include <QDebug>
#include <QThread>
#include <QTimer>class Worker : public QObject
{Q_OBJECTpublic:Worker() = default;signals:void finished();public slots:void longRunningTask(){// 模拟耗时任务qDebug() << "Long running task started in thread:" << QThread::currentThreadId();for (int i = 0; i < 10; ++i){qDebug() << "Processing..." << i;QThread::sleep(1); // 模拟耗时操作}qDebug() << "Long running task finished in thread:" << QThread::currentThreadId();emit finished();}
};
2. 主线程中启动工作线程
#include <QCoreApplication>
#include <QThread>
#include "Work.h"int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);// 创建工作线程对象Worker *worker = new Worker; // 工作对象QThread *thread = new QThread;// 将工作对象移动到工作线程worker->moveToThread(thread);// 启动线程QObject::connect(thread, SIGNAL(started()), worker, SLOT(longRunningTask()));QObject::connect(worker, &Worker::finished, [&app]() {qDebug() << "Worker finished, quitting application...";app.quit(); // 当工作完成后通知主事件循环退出});QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));QObject::connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));thread->start(); // 启动线程,触发 started 信号,进而调用 longRunningTask// 主线程继续执行其他任务qDebug() << "Main thread is running other tasks...";return app.exec();
}
三、代码说明
- 工作线程类:
Worker类继承自QObject,并在其中定义了耗时任务longRunningTask。- 使用
QThread::sleep(1)模拟耗时操作。
- 主线程中启动线程:
- 创建
Worker对象和QThread对象。 - 使用
moveToThread()将Worker对象移动到工作线程。 - 使用
connect()连接线程的started信号到Worker的longRunningTask槽函数。 - 启动线程后,
Worker的longRunningTask会在工作线程中异步执行。
- 创建
- 主线程继续执行:
- 主线程在启动工作线程后,可以继续执行其他任务,例如
qDebug()输出或其他逻辑。
- 主线程在启动工作线程后,可以继续执行其他任务,例如
四、代码运行结果:

五、遇到问题
1.QThread: Destroyed while thread is still running.
原始程序:
#include <QCoreApplication>
#include <QThread>
#include "Work.h"int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);// 创建工作线程对象Worker worker;QThread thread;// 将工作对象移动到工作线程worker.moveToThread(&thread);// 启动线程QObject::connect(&thread, &QThread::started, &worker, &Worker::longRunningTask);QObject::connect(&worker, &Worker::finished, &thread, &QThread::quit);QObject::connect(&worker, &Worker::finished, &worker, &Worker::deleteLater);QObject::connect(&thread, &QThread::finished, &thread, &QThread::deleteLater);thread.start(); // 启动线程,触发 started 信号,进而调用 longRunningTask// 主线程继续执行其他任务qDebug() << "Main thread is running other tasks...";QTimer::singleShot(5000, &app, &QCoreApplication::quit); // 5秒后退出程序return app.exec();
}
2.运行Qt程序报错 Expression: _CrtIsValidHeapPointer(block).
原始代码程序:
#include <QCoreApplication>
#include <QThread>
#include "Work.h"int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);// 创建工作线程对象// Worker *worker = new Worker; // 工作对象// QThread *thread = new QThread;Worker worker; // 工作对象QThread thread;// 将工作对象移动到工作线程worker.moveToThread(&thread);// 启动线程QObject::connect(&thread, SIGNAL(started()), &worker, SLOT(longRunningTask()));// QObject::connect(worker, &Worker::finished, [&app]() {// qDebug() << "Worker finished, quitting application...";// app.quit(); // 当工作完成后通知主事件循环退出// });QObject::connect(&worker, SIGNAL(finished()), &thread, SLOT(quit()));QObject::connect(&worker, SIGNAL(finished()), &worker, SLOT(deleteLater()));QObject::connect(&thread, SIGNAL(finished()), &thread, SLOT(deleteLater()));thread.start(); // 启动线程,触发 started 信号,进而调用 longRunningTask// 主线程继续执行其他任务qDebug() << "Main thread is running other tasks...";return app.exec();
}
错误信息 Expression: _CrtIsValidHeapPointer(block) 通常出现在使用 Visual Studio 的调试版本运行程序时,这表示你的程序试图访问一个无效的堆指针。这种情况通常是由于内存管理问题引起的,例如双重释放、访问已经释放的内存或者在栈上分配的对象被错误地传递给需要堆分配对象的函数。
以下是一些可能的原因和解决方法:
-
双重释放:确保每个通过
new分配的内存只调用一次delete,避免对同一个指针多次调用delete。 -
访问已释放的内存:检查代码中是否存在指向已释放内存的悬空指针,并确保在释放内存后将这些指针设置为
nullptr或者不再使用它们。 -
不正确的内存分配/释放匹配:确保你使用的是正确的内存分配和释放函数对。比如,如果你使用
malloc分配内存,请使用free而不是delete来释放它;如果你使用new[]来分配数组,请使用delete[]而不是delete来释放。 -
多线程环境下的竞争条件:如果在多线程环境下工作,确保对共享资源的访问是线程安全的。可以使用互斥锁等同步机制来防止数据竞争。
-
Qt 对象树机制误用:Qt 使用父对象-子对象关系自动管理对象的生命周期。确保正确设置了 QObject 及其子类的父子关系,避免手动删除由 Qt 自动管理的对象。
-
Debug 和 Release 混淆:确保你的项目配置(如链接的库)与构建类型(Debug或Release)相匹配。不要在 Debug 配置中链接到 Release 库,反之亦然。
要诊断这个问题,你可以尝试以下步骤:
- 使用调试器逐步执行代码,观察在哪个点出现问题。
- 使用工具如 Valgrind (Linux), AddressSanitizer, 或者 Visual Studio 自带的诊断工具来检测内存泄漏和非法内存访问。
- 检查最近修改过的代码部分,特别是涉及到动态内存分配和释放的地方。
通过仔细检查你的代码并遵循上述建议,你应该能够找到导致该错误的具体原因并加以修复。
3.Terminal process exited with code 62097.qtc.process_stub: Inferior error: QProcess::Crashed “Process crashed”
原始程序:
#include <QCoreApplication>
#include <QThread>
#include "Work.h"int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);// 创建工作线程对象Worker *worker = new Worker; // 工作对象QThread *thread = new QThread;// 将工作对象移动到工作线程worker->moveToThread(thread);// 启动线程QObject::connect(thread, SIGNAL(started()), worker, SLOT(longRunningTask()));// QObject::connect(worker, &Worker::finished, [&app]() {// qDebug() << "Worker finished, quitting application...";// app.quit(); // 当工作完成后通知主事件循环退出// });QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));QObject::connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));thread->start(); // 启动线程,触发 started 信号,进而调用 longRunningTask// 主线程继续执行其他任务qDebug() << "Main thread is running other tasks...";return app.exec();
}
程序运行结束后报错 “Terminal process exited with code 62097.qtc.process_stub: Inferior error: QProcess::Crashed”,这通常意味着程序在退出时发生了崩溃。以下是一些可能的原因及解决办法:
- 确保信号和槽正确连接:确认所有信号和槽的连接都是正确的,并且没有拼写错误。特别是检查
Worker类中的finished()信号是否正确发出。 - 避免悬空指针问题:虽然你在
Worker对象上使用了deleteLater(),但在某些情况下,如果对象被提前销毁或者存在其他指针访问已释放的对象,可能会导致崩溃。 - 主线程退出时机:确保当应用程序退出时,所有工作线程都已经完成并正确关闭。如果主线程过早退出而工作线程仍在运行,可能会导致未定义行为或崩溃。
- 资源清理:确保所有的资源(如文件、网络连接等)都被正确释放。
在改进版本中,我们通过连接 Worker 的 finished() 信号到一个 lambda 表达式,该表达式会调用 app.quit() 来请求 Qt 应用程序主事件循环退出。这样可以确保当工作线程完成任务后,主事件循环能够有序地退出,从而减少崩溃的可能性。
相关文章:
Qt中如果槽函数运行时间久,避免阻塞主线程的做法
Qt中如果槽函数运行时间久,避免阻塞主线程的做法 一、解决步骤 创建一个工作线程类:继承自QObject,并在其中实现槽函数的逻辑。将工作线程类的实例移动到单独的线程中:通过moveToThread()方法将对象移动到新线程。启动线程&…...
曹操智行构建国内首个全域自研闭环智驾生态
2月28日,曹操出行举办曹操智行自动驾驶平台上线仪式,宣布已成功构建国内首个“F立方”全域自研闭环智驾生态,同时在苏杭两地开启Robotaxi运营试点,并投放搭载吉利最新智驾系统的车辆。 此次试点运营,标志着曹操出行在…...
day02_Java基础
文章目录 day02_Java基础一、今日课程内容二、数组(熟悉)1、定义格式2、基本使用3、了解数组的内存图介绍4、数组的两个小问题5、数组的常见操作 三、方法(熟悉)1、定义格式2、方法重载overload 四、面向对象(掌握&…...
SpringSecurity 实现token 认证
配置类 Configuration EnableWebSecurity EnableGlobalMethodSecurity(prePostEnabledtrue) public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { Bean Override public AuthenticationManager authenticationManagerBean() throws Exception {return s…...
轻松实现语音生成:GPT-SoVITS V2整合包的远程访问操作详解
文章目录 前言1.GPT-SoVITS V2下载2.本地运行GPT-SoVITS V23.简单使用演示4.安装内网穿透工具4.1 创建远程连接公网地址 5. 固定远程访问公网地址 前言 今天要给大家安利一个绝对能让你大呼过瘾的声音黑科技——GPT-SoVITS!这款由花儿不哭大佬精心打造的语音克隆神…...
解锁状态模式:Java 编程中的行为魔法
系列文章目录 后续补充~~~ 文章目录 一、状态模式:概念与原理二、状态模式的深度剖析(一)模式定义与核心思想(二)模式结构与角色 三、状态模式的实际应用场景(一)电商系统中的订单状态管理&…...
算法与数据结构(相交链表)
题目 思路 1.哈希集合 因为要求是否存在相交节点,那么我们就可以利用哈希集合先将listA链表里面的所有数据存入,然后访问listB,判断其是否有节点在哈希集合中,若存在,则说明此节点为相交的节点。若遍历完之后仍没有发…...
浅入浅出Selenium DevTools
前言 在自动化测试领域,Selenium一直是主流工具之一。随着前端技术的不断发展,浏览器的功能也在不断丰富。 Selenium 3版本前,一套通用的采集流程如上图所示: 打开Charles,设置Session自动导出频次及导出路径Seleniu…...
软件工程---净室软件工程
净室软件工程是一种软件开发方法,旨在通过形式化的数据和严格的测试来提高软件的可靠性和减少缺陷的数量。它的核心思想是在软件开发过程中最小化或消除软件缺陷,从而提高软件的质量和可靠性。这种方法强调在软件生命周期的早期阶段使用形式化方法进行规…...
OpenHarmony图形子系统
OpenHarmony图形子系统 图形子系统主要包括UI组件、布局、动画、字体、输入事件、窗口管理、渲染绘制等模块,构建基于轻量OS应用框架满足硬件资源较小的物联网设备或者构建基于标准OS的应用框架满足富设备的OpenHarmony系统应用开发。 1.1 轻量系统 简介 图形子…...
如何获取Mac OS 安装盘
发现虚拟机VirtualBox支持Mac虚拟,就想尝试一下。但是发现Mac的安装盘特别难拿到,因此留档。发现有几种方法,最简单的方法,是在有Mac 机器的情况下,直接到App Store里,根据Mac版本的名字查找并下载。另外还…...
【弹性计算】弹性裸金属服务器和神龙虚拟化(一):功能特点
弹性裸金属服务器和神龙虚拟化(一):功能特点 特征一:分钟级交付特征二:兼容 VPC、SLB、RDS 等云平台全业务特征三:兼容虚拟机镜像特征四:云盘启动和数据云盘动态热插拔特征五:虚拟机…...
大白话前端性能优化方法的分类与具体实现
大白话前端性能优化方法的分类与具体实现 一、资源加载优化 1. 压缩与合并文件 大白话解释: 咱们的网页代码里,就像一个房间堆满了东西,有很多没用的“杂物”,比如代码里的空格、注释啥的。压缩文件就是把这些“杂物”清理掉&a…...
Rabbit MQ 高频面试题【刷题系列】
文章目录 一、公司生产环境用的什么消息中间件?二、Kafka、ActiveMQ、RabbitMQ、RocketMQ有什么优缺点?三、解耦、异步、削峰是什么?四、消息队列有什么缺点?五、RabbitMQ一般用在什么场景?六、简单说RabbitMQ有哪些角…...
ES6 特性全面解析与应用实践
1、let let 关键字用来声明变量,使用let 声明的变量有几个特点: 1) 不允许重复声明 2) 块儿级作用域 3) 不存在变量提升 4) 不影响作用域链 5) 暂时性死区 6)不与顶级对象挂钩 在代码块内,使用let命令声明变量之前&#x…...
有关数据库表的冗余字段
有关数据库表的冗余字段 之前看一个开发人员的技术研讨视频,提到了一个数据库表设计中的表拆分字段冗余问题,就是一张表做纵向分表,拆分为a和b以做冷热数据分离存储,但是会有一种情况就是相同的字段值在a,b表中重复出现…...
知识图谱补全KGC
目录 基础知识知识图谱补全概念性能指标 一、翻译模型的知识图谱补全1.TransE2.TransH3.RotatE 二、张量分解的知识补全1.RESCAL2.ComplEx 三、神经网络的知识图谱补全1.卷积神经网络CNN(一般用于二维图像处理)ConvE 2.循环神经网络RNN3.图神经网络GNN1&…...
独立开发者的内容营销教程
内容营销对于独立开发者来说,是一种低成本、高效的方式来推广产品、建立品牌影响力和吸引潜在用户。通过分享有价值、相关性强的内容,您可以吸引用户的注意力,增强用户黏性,并最终将他们转化为忠实用户或客户。以下是详细的独立开…...
Mysql——约束与多表查询
一、约束 1.1定义 约束是对表中的数据进行限制的一套规则,用于防止用户向数据库中输入无效数据。它可以保证表中的数据满足特定业务规则和逻辑,从而维护数据的准确性和可靠性。 1.2作用 数据完整性 :约束可以确保数据在插入、更新或删除时符…...
DockerでOracle Database 23ai FreeをセットアップしMAX_STRING_SIZEを拡張する手順
DockerでOracle Database 23c FreeをセットアップしMAX_STRING_SIZEを拡張する手順 はじめに環境準備ディレクトリ作成Dockerコンテナ起動 データベース設定変更コンテナ内でSQL*Plus起動PDB操作と文字列サイズ拡張設定検証 管理者ユーザー作成注意事項まとめ はじめに Oracle…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
