当前位置: 首页 > news >正文

Qt 子线程中无限递归的信号槽导致主线程槽失效的原因和解决办法

Qt 子线程中无限递归的信号槽导致主线程槽失效的原因和解决办法

问题描述

在一个 Qt6.5.3 的项目中,有一个 ImageProcessor 类负责在子线程中进行图像处理,并有一个 MainWindow 类在主线程中进行界面更新。虽然 ImageProcessor::processingDone 信号被成功触发,但 MainWindow::updateScene 槽函数却没有被调用。这里详细描述一下涉及的代码和逻辑。

代码架构与流程

ImageProcessor 类

该类在一个独立的线程中运行,并负责图像处理。当图像处理完成后,它会发出一个 processingDone 信号。

class ImageProcessor : public QObject
{Q_OBJECTpublic:// ... 构造函数和其他成员函数signals:void processingDone(QVector<DetectResult> detectResult);public slots:void processImage(){// ... 图像处理逻辑emit processingDone(res);}void onProcessingDone(const QVector<DetectResult>){processImage();}
};// 在构造函数中
ImageProcessor::ImageProcessor(/* ... */)
{connect(this, &ImageProcessor::processingDone, this, &ImageProcessor::onProcessingDone);
}
MainWindow 类

该类运行在主线程中,负责接收 ImageProcessorprocessingDone 信号,并通过 updateScene 槽函数进行处理。

class MainWindow : public QMainWindow
{Q_OBJECTpublic:// ... 构造函数和其他成员函数public slots:void updateScene(QVector<DetectResult> detectResult){// ... 更新界面逻辑}
};// 在构造函数中
MainWindow::MainWindow(QWidget* parent)
{// ... 创建 ImageProcessor 和子线程QObject::connect(imageProcessor, &ImageProcessor::processingDone, this, &MainWindow::updateScene);
}

递归调用

ImageProcessor 类中,processingDone 信号和 onProcessingDone 槽函数被连接了起来,而 onProcessingDone 函数内部又调用了 processImage,这导致了无限递归。

void ImageProcessor::onProcessingDone(const QVector<DetectResult>)
{processImage();
}

由于这种递归持续发生在子线程中,它占据了所有可用的事件循环时间,因此 MainWindow::updateScene 没有机会被执行。

解决方案

修改 ImageProcessor 类的构造函数,使用 Qt::QueuedConnection 来连接 processingDoneonProcessingDone

ImageProcessor::ImageProcessor(/* ... */)
{connect(this, &ImageProcessor::processingDone, this, &ImageProcessor::onProcessingDone, Qt::QueuedConnection);
}

这样,onProcessingDone 将在下一个事件循环周期中被调用,给其他等待的槽函数(如 MainWindow::updateScene)提供了执行的机会。

总结

在 Qt 的多线程环境中使用信号和槽时,需要特别小心潜在的递归和事件循环阻塞问题。正确地设置信号和槽的连接类型和执行顺序是避免这类问题的关键。希望本文能为您提供有用的信息和解决方案。

http://www.lryc.cn/news/193122.html

相关文章:

  • 实施 DevSecOps 最佳实践
  • 第56节——redux-toolkit中的createAction——了解
  • 【数据结构】排序--选择排序(堆排序)
  • C# 图解教程 第5版 —— 第2章 C# 和 .NET Core
  • 数据结构 | Huffman TreeCode
  • mysql拼接字符串函数
  • python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域
  • 《动手学深度学习 Pytorch版》 8.6 循环神经网络的简洁实现
  • leetcode做题笔记173. 二叉搜索树迭代器
  • RPA流程自动化的优势和好处
  • 搭建 Hadoop 生态集群大数据监控告警平台
  • 课题学习(七)----粘滑运动的动态算法
  • python二次开发CATIA:测量曲线长度
  • 从零开始学习调用百度地图网页API:二、初始化地图,鼠标交互创建信息窗口
  • Yarn基础入门
  • element picker 时间控件,指定区间和指定月份置灰
  • thinkphp6
  • Android 13.0 USB鼠标右键改成返回键的功能实现
  • 超低延时 TCP/UDP IP核
  • Python与数据库存储
  • RN操作SQLite数据库的包(sqlite-helper.js)及其使用
  • 软件测试学习(四)自动测试和测试工具、缺陷轰炸、外包测试、计划测试工作、编写和跟踪测试用例
  • 【Rust日报】2023-10-12 论文:利用公共信息评估 Rust 代码库
  • 微信小程序入门
  • 【RocketMQ系列二】通过docker部署单机RocketMQ
  • 中缀表达式转后缀表达式
  • Zabbix 使用同一ODBC监控不同版本MySQL
  • Swagger3.0 与spring boot2.7x 整合避免swagger2.0与boot2.7冲突
  • 【HTML+REACT+ANTD 表格操作】处理(改变)数据,改变DOM
  • 【面试经典150 | 哈希表】最长连续序列