0

I have a Qt GUI application which does some I/O bound work when a button is pressed. In order to avoid GUI not being responsive, I created a new thread and move the work there:

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

I detach the thread immediately. The other function simply does the real work:

void on_process_button_clicked_real_work() const
{
    std::lock_guard<std::mutex> lock(mutex);

    // Some irrelevant code ...
}

The GUI now doesn't entirely freeze, I can still see it updated, but it becomes really unresponsive and laggy.

Questions:
1. Why does this happen?
2. How may I fix it?

I have seen many similar question, but most are about QThread so I couldn't solve my problem.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/191800/discussion-on-question-by-ayxan-qt-gui-hangs-despite-threading). – Bhargav Rao Apr 13 '19 at 23:07

1 Answers1

2

Turns out the problem is I was using QFileSystemModel (not in this function but in general) to show a list of files in the folder and this answer points out:

QFileSystemModel lists directories on a background thread to avoid blocking the UI. However, once it gets a list of updates in QFileSystemModelPrivate::_q_fileSystemChanged it then fetches the icons for the file in the main thread using QFileInfoGatherer::getInfo() which in turn calls QFileIconProvider::icon(QFileInfo).

The problem is that QFileSystemModel constantly updates the GUI while the new thread rapidly creates/removes files and that causes the laggy experience. I don't know how to stop or delay updates in that model, but what I did is changing rootPath to "" and changing it back once the function finishes the work:

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);
}

Implementing some kind of lock object to be exception safe and make sure the rootPath is set back is probably the most optimal way.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • If `model` is your QFSM, you are not allowed to touch it outside the GUI thread, no matter what's the amount of locking you put on it. You need to "disable" it from the GUI thread itself. – peppe Apr 14 '19 at 23:08
  • @peppe and how do I disable it? – Aykhan Hagverdili Apr 15 '19 at 03:12
  • Either from the function that spawns the thread (so, basically, from the GUI thread itself). Or, emit signals / use queued invocations from the worker thread. – peppe Apr 15 '19 at 09:57
  • @peppe is there a way to disable QFSM other than altering the rootPath? – Aykhan Hagverdili Apr 18 '19 at 19:00