尽管有线程,Qt GUI 仍挂起

Posted

技术标签:

【中文标题】尽管有线程,Qt GUI 仍挂起【英文标题】:Qt GUI hangs despite threading 【发布时间】:2019-04-13 10:26:38 【问题描述】:

我有一个 Qt GUI 应用程序,它在按下按钮时执行一些 I/O 绑定工作。为了避免 GUI 没有响应,我创建了一个新线程并将工作移到那里:

private slots:
    inline void on_process_button_clicked() const
    
        std::thread thread(&My_class::on_process_button_clicked_real_work, this);
        thread.detach();
    

我立即分离线程。另一个函数只是做真正的工作:

void on_process_button_clicked_real_work() const

    std::lock_guard<std::mutex> lock(mutex);

    // Some irrelevant code ...

GUI 现在并未完全冻结,我仍然可以看到它已更新,但它变得非常无响应且迟滞。

问题: 1. 为什么会这样? 2. 我该如何解决?

我见过manysimilarquestion,但大多数都是关于QThread,所以我无法解决我的问题。

【问题讨论】:

评论不用于扩展讨论;这个对话是moved to chat。 【参考方案1】:

原来问题是我使用QFileSystemModel(不是在这个函数中,而是在一般情况下)显示文件夹中的文件列表,this 回答指出:

QFileSystemModel 列出后台线程上的目录以避免 阻止用户界面。但是,一旦它获得更新列表 QFileSystemModelPrivate::_q_fileSystemChanged 然后它会获取 主线程中文件的图标使用 QFileInfoGatherer::getInfo() 依次调用 QFileIconProvider::icon(QFileInfo).

问题在于QFileSystemModel 在新线程快速创建/删除文件时不断更新 GUI,这会导致体验滞后。我不知道如何停止或延迟该模型中的更新,但我所做的是将 rootPath 更改为 "" 并在函数完成工作后将其改回:

void on_process_button_clicked_real_work() const

    std::lock_guard<std::mutex> lock(mutex);
    auto path = model.rootPath();
    model.setRootPath("");

    // Some irrelevant code ...

    model.setRootPath(path);

实现某种锁定对象以确保异常安全并确保rootPath 被设置回可能是最佳方式。

【讨论】:

如果model 是您的QFSM,则不允许在GUI 线程之外触摸它,无论您对其施加的锁定量是多少。您需要从 GUI 线程本身“禁用”它。 @peppe 我该如何禁用它? 来自产生线程的函数(所以,基本上,来自 GUI 线程本身)。或者,从工作线程发出信号/使用排队调用。 @peppe 除了更改 rootPath 之外,有没有办法禁用 QFSM?

以上是关于尽管有线程,Qt GUI 仍挂起的主要内容,如果未能解决你的问题,请参考以下文章

某些数据处理时 MFC 应用程序 gui 挂起

程序崩溃后如何挂起所有线程?

Qt多线程编程总结(所有GUI对象都是线程不安全的)

QThread 和 GUI 线程说明

Qt多线程和GUI界面假死

响应式 Qt GUI,即使是线程