1

I would like to find an easy way to start a lengthy operation from my application's main gui thread. I have his exporter object that is not affiliated to any thread.

void closeExporter()
{  
    // Run closing of object in a different thread:
        QFuture<void> future = QtConcurrent::run([=]()
        {
            m_pExporter->close();
        });

        while (!future.isFinished())
        {
            QApplication::processEvents();
        //  QThread::msleep(0);
            qDebug() << "waiting!";
        }
}   

I am not using waitForFinished() function then it blocks any my gui thread becomes unresponsive. It works fine for a while put the debug printing stop and my application will still become unresponsive. Dies somebody have an idea why this is happening?

Benjamin Bihler
  • 1,612
  • 11
  • 32
Richy
  • 534
  • 4
  • 13

2 Answers2

0

I think, that you should use QFutureWatcher as a possible implementation. The following small example illustrates the usage.

#include <QApplication>
#include <QFrame>
#include <QDebug>
#include <QHBoxLayout>
#include <QPushButton>
#include <QThread>
#include <QObject>
#include <QFutureWatcher>
#include <QMessageBox>
#include <QtConcurrent>

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    auto frame = new QFrame;
    frame->setLayout(new QHBoxLayout);
    auto btn = new QPushButton("Start Thread");
    frame->layout()->addWidget(btn);

    QThread::currentThread()->setObjectName("Main Thread");

    QFutureWatcher<void> watcher;
    QObject::connect(&watcher, &QFutureWatcher<void>::finished, [frame,btn]() {
        QMessageBox::information(frame, "Done", QThread::currentThread()->objectName(), QMessageBox::StandardButton::Ok);
        btn->setEnabled(true);
    });

    QObject::connect(btn, &QPushButton::clicked, [btn,&watcher](){
        QFuture<void> future = QtConcurrent::run([]() {
            QThread::msleep(6000);
            qDebug() << QThread::currentThread()->objectName();
        });
        watcher.setFuture(future);
        btn->setDisabled(true);
    });

    frame->show();

    return a.exec();
}
Aleph0
  • 5,816
  • 4
  • 29
  • 80
  • 1
    I think that connect is dangerous, because you can't control in which context the message box is opened, without passing a context pointer. If the finished signal is emitted in another thread, then your code has undefined behavior. – Johannes Schaub - litb Aug 13 '19 at 07:56
  • @JohannesSchaub-litb: Many thanks for your advice, but I really didn't got it. I just changed my answer. The message box always shows the message `Main Thread`, whereas the lamba function displays `Thread (pooled)`. The program never crashed on my machine. Maybe you can be more concrete, as my experience with multi-threaded is really basic. – Aleph0 Aug 13 '19 at 08:06
0

The original code was working fine after all. Sorry to burn your time.

Richy
  • 534
  • 4
  • 13