Как сделать часть функции отдельным потоком?

Возможно изобретаю велосипед, хочется узнать все ли корректно (возможно у моей реализации не все учтено), или можно лучше, проще?

Есть ф-ция MainWindow::someSlot, где определенную часть (MainWindow::veryLongFunc) необходимо делать отдельным потоком, чтобы интерфейс не зависал.

#mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT    
public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    int otherFields() const;
    void setOtherFields(int otherFields);

public slots:
    void someSlot();
private:
    void veryLongFunc();
    Ui::MainWindow *ui;
    int _otherFields;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtConcurrent>
#include <future>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
}

void MainWindow::someSlot() {
    /* some code */
    QFuture<void> t = QtConcurrent::run([this] { veryLongFunc(); });
    while(!t.isFinished()) {
        QApplication::processEvents();
    }
    /* some code */
}

void MainWindow::veryLongFunc() {
    /* very long func */
}

int MainWindow::otherFields() const
{
    return _otherFields;
}

void MainWindow::setOtherFields(int otherFields)
{
    _otherFields = otherFields;
}

MainWindow::~MainWindow() { delete ui; }

Ответы (1 шт):

Автор решения: Alexander Chernin

Не надо делать while(!t.isFinished()) {} - вы тормозите главный поток приложения (со всем его GUI) до тех пор, пока поток функции не выполнит свою работу.

Как я указал в комментарии, вам нужно воспользоваться классом QFutureWatcher, который просигнализирует нам об завершении выполнения функции в потоке.

Заведите объект класса QFutureWatcher в MainWindow:

class MainWindow : ... {
private:
    QFutureWatcher<void> _watcher;
}

В конструкторе MainWindow:

MainWindow::MainWindow():... {
    connect(&_watcher, &QFutureWatcher<void>::finished, [&](){
        qDebug() << "VeryLongFunction's job is done!";
    });
}

Далее:

void MainWindow::someSlot() {
    QFuture<void> t = QtConcurrent::run([this] { veryLongFunc(); });
    _watcher.setFuture(t);
}

Таким образом, вы избежите отсутствия отклика от GUI во время работы ОченьДлиннойФункции

→ Ссылка