Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to terminate async function when the Qt dialog is closed

Background

I have a dialog which runs a time-consuming operation on its initialization. I wrapped this operation into an asynchronous function in order not to freeze the GUI.

Example

Imagine a dialog/widget which shows the current weather fetched asynchronously from a remote server:

Dialog::Dialog()
{
    auto label = new QLabel(this);
    QtConcurrent::run([=]() {
        const int temperature = getWeather(); // Time-consuming function
        label->setText(temperature);
    });
    // The rest code, layouts initialization, etc.
}

Problem

If this dialog/widget is closed before the asynchronous operation is finished, the label->setText() part will obviously lead to a crash because the widget object won't exist by that moment.

Question

What is the proper way to deal such situations? Probably, I should use something else instead of QtConcurrent (QThread, for example) in order to properly cancel the asynchronous function when the dialog is closed.

Note

Note that the actual code is about reading a bunch of files, not about networking, that's why using the async QNetworkRequest interface is not a case.

like image 505
John Doe Avatar asked Dec 13 '25 04:12

John Doe


1 Answers

// global or class member
QFutureWatcher<int> g_watcher;

Dialog::Dialog()
{
    connect(&g_watcher, &QFutureWatcher<int>::finished, this, &Dialog::handleFinished);

    QFuture<int> future = QtConcurrent::run([]() -> int
    {
        int temperature = getWeather(); // Time-consuming function

        return temperature;
    });

    g_watcher.setFuture(future);
}

void Dialog::handleFinished()
{
    // will never crash because will not be called when Dialog destroyed
    ui->label->setText(QString::number(g_watcher.result()));
}

There is also possible to disconnect everything connected to the finished signal:

disconnect(&g_watcher, &QFutureWatcher<int>::finished, 0, 0);

p.s. As for cancel the async operation, it cannot be cancelled correctly by QtConcurrent or QThread methods.

There is QThread::terminate() method, but from the doc:

...Warning: This function is dangerous and its use is discouraged. The thread can be terminated at any point in its code path...

Therefore you have to implement some "cancel" flag inside your getWeather() function, or do as written above.

like image 118
Vladimir Bershov Avatar answered Dec 16 '25 01:12

Vladimir Bershov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!