0

My code sometimes crashes due to future's async.

This is not production code, just very simple stuff for demonstrating what i want to do.

I have to download some info and then return first obtained result. Just imagine i do not want to wait so i'm using QFutureWatcher too speed up the downloading.

When i obtained the result (first or second instance) i want to return the result IMMEDIATELY (i mean i do not want to use QFutureWatcher::waitForFinished. (If i received finished signal from first instance, i no longer need the second one. Or the same for the first.

In production code function download i cannot access to QNetworkReply, so the pending request could not be aborted.

Sometimes this code crashes. What am i doing wrong?

#include <QFutureWatcher>
#include <QtConcurrent>
#include <QEventLoop>
#include <QTimer>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetworkAccessManager>

QByteArray download(const QUrl &url)
{
    QNetworkAccessManager manager;
    QNetworkRequest req(url);
    req.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
    QNetworkReply *reply = manager.get(req);
    reply->deleteLater();
    return reply->readAll();
}

QByteArray downloadSmth(const QUrl &urlFirst, const QUrl &urlSecond)
{
    typedef QFutureWatcher<QByteArray> FutureWatcher;
    FutureWatcher *first = new FutureWatcher;
    FutureWatcher *second = new FutureWatcher;

    QByteArray res;

    QEventLoop loop;
    QObject::connect(first, &FutureWatcher::finished, [&res, &loop, first] {
        res = first->result();
        loop.quit();
    });
    QObject::connect(second, &FutureWatcher::finished, [&res, &loop, second] {
        res = second->result();
        loop.quit();
    });
    QTimer timer;
    timer.setSingleShot(true);
    QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);



    first->setFuture(
        QtConcurrent::run([&urlFirst] {
            return download(urlFirst);
        }));

    second->setFuture(
        QtConcurrent::run([&urlSecond] {
            return download(urlSecond);
        }));


    timer.start(60 * 1000);
    loop.exec();

    if (timer.isActive()) {
        timer.stop();
    }

    first->deleteLater();
    second->deleteLater();
    return res;
}
Jamie
  • 1
  • 1
  • Do you need to use pointers? Will it work if you use a `QFutureWatcher` instead of `QFutureWatcher*`? – JarMan Aug 04 '20 at 21:12
  • Yes, it will work. But the problem in QtConcurrent::run that crashes my program (i have to wait until it's finished) – Jamie Aug 04 '20 at 21:17
  • If i remove download source code and put it to return some str - it works perfectly – Jamie Aug 04 '20 at 21:20
  • It's crashing in the download function? – JarMan Aug 04 '20 at 21:21
  • Correct! If i use download function out of QFutureWatcher - i have no problems – Jamie Aug 04 '20 at 21:22
  • The [docs](https://doc.qt.io/qt-5/qfuturewatcher.html#cancel) say QtConcurrent::run cannot be cancelled. So I think you either need to wait until they're both finished, or change how you've designed this function. – JarMan Aug 04 '20 at 21:32
  • Could you help me with redesigning this function? I don't know how to implement this in other way – Jamie Aug 04 '20 at 21:34

0 Answers0