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


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

    问题描述

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

    代码架构与流程

    ImageProcessor 类

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

    class ImageProcessor : public QObject
    {
        Q_OBJECT
    
    public:
        // ... 构造函数和其他成员函数
    
    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    MainWindow 类

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

    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        // ... 构造函数和其他成员函数
    
    public slots:
        void updateScene(QVector<DetectResult> detectResult)
        {
            // ... 更新界面逻辑
        }
    };
    
    // 在构造函数中
    MainWindow::MainWindow(QWidget* parent)
    {
        // ... 创建 ImageProcessor 和子线程
        QObject::connect(imageProcessor, &ImageProcessor::processingDone, this, &MainWindow::updateScene);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    递归调用

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

    void ImageProcessor::onProcessingDone(const QVector<DetectResult>)
    {
        processImage();
    }
    
    • 1
    • 2
    • 3
    • 4

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

    解决方案

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

    ImageProcessor::ImageProcessor(/* ... */)
    {
        connect(this, &ImageProcessor::processingDone, this, &ImageProcessor::onProcessingDone, Qt::QueuedConnection);
    }
    
    • 1
    • 2
    • 3
    • 4

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

    总结

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

  • 相关阅读:
    TVP专家谈腾讯云 Cloud Studio:开启云端开发新篇章
    逆序对专题
    C++——智能指针
    学生作业管理系统的设计与实现-计算机毕业设计源码20912
    stable diffusion webui安装部署教程
    Qt5.14.2 大文件处理的Qt多线程黑科技
    flink cdc多种数据源安装、配置与验证
    TMall商城系统订单模块分析(3)
    Bluespec SytemVerilog 握手协议接口转换
    Flow Problem(最大流模板)
  • 原文地址:https://blog.csdn.net/qq_42896106/article/details/133778493