Qt World Summit: Register Today!

Freeze in multithreaded program

  • Hi,

    I've been writing a small update software for a video game, using Qt 4.8. The software features a FTP client, a basic UI a some extensions (launch the game, etc). The source code is available on Github : https://github.com/arbonagw/UnrealUpdater .
    I'm experiencing weird UI freezes where it should not, so I'll explain how it works.

    I've got a main class, Updater, that launches a second thread with a worker class, Downloader, that uses QNetworkAccessManager to download files. Here is the process :

    • it starts by downloading a manifest file with a tree of file names along with MD5 hash ;
    • then it computes a list of files to update by checking each of these files locally with their MD5, this work is done with QtConcurrent::run() ;
    • after that, Updater sends a file name, Downloader signals when it's done, and so on.
    • when the list of files is empty, it starts the game.

    Now I've got three problems :

    • while computing the MD5, checking the files, the UI is frozen. There is just no reason, it's supposed to be done in a separate thread ;
    • -while downloading, I receive the "finished" event from QNetworkAccessManager in multiple occurrences. The first finished() is sent once, the second is sent twice, and so on. What he hell ?- (my bad, found that out)
    • the downloading process looks prone to freezing randomly while downloading (no downloading, but a responsive UI that can open dialogs when pressing buttons).

    I fail to understand how this is is failing. Can anyone help with the software structure ? What is actually wrong here ?

    Thanks !

  • See at this:
    QFuture<void> parser = QtConcurrent::run(this, &Updater::GetFilesToDownload, *dom, QString(""));

    you block your main thread waiting for computation result. You should use QFutureWatcher to make it asynchronous and non-blocking.

  • Moderators

    Edit: And Bogdan has beaten me to it :D

    Your code has
    QFuture<void> parser = QtConcurrent::run(this, &Updater::GetFilesToDownload, *dom, QString(""));

    ...and it looks like the hashing is done within Updater::GetFilesToDownload().

    Yes, Updater::GetFilesToDownload() is being run in other threads, BUT you've asked your program to wait until all downloading and hashing have finished. So, the main thread (which handles the GUI) will wait -- i.e. freeze -- while your hashes are being computed.

    Here's a possible solution: Instead of using waitForFinished(), attach a QFutureWatcher to your QFuture, and let your main thread continue running. Then, get the QFutureWatcher to emit a signal once your hashes are done. Qt is an event-driven framework -- use that to your advantage :)

  • Wow thanks ! I understand, I did not think of that.
    I just fixed my code, this problem is gone now. One down !

    @QFutureWatcher<void>* watcher = new QFutureWatcher<void>();
    connect(watcher, SIGNAL(finished()), this, SLOT(StartDownload()));
    QFuture<void> parser = QtConcurrent::run(this, &Updater::GetFilesToDownload, *dom, QString(""));

    There is one issue left - the download stops randomly. I added some qDebug here and there, I find that I just stop receiving events from QNetworkAccessManager. It can't be a Qt bug since I was isung QFtp before...

    I also have minor freezing when moving the window around while downloading so I guess there is more failure where the first one came from...

  • Moderators

    How many requests do you send to the server at a time? I've found that if I send too many requests simultaneously, strange things happen to the connection. For one of my programs, I ended up queueing my downloads manually and making sure that only one file is being downloaded at a time. It's slower, but much more stable.

  • I only send one request at a time and wait for the answer.
    Now, I do have a workaround for the problem (reset the downloader and restart on timeout) but that's hardly a fix...

  • Moderators

    [quote author="GwennH" date="1367224499"]I only send one request at a time and wait for the answer.
    Now, I do have a workaround for the problem (reset the downloader and restart on timeout) but that's hardly a fix...[/quote]I think that's a generic networking issue. Sometimes my browser download stalls too, and needs to be restarted. My workaround for that is to use a download manager (but I don't think QNetworkAccessManager has one built-in, unfortunately)

  • Yes, that's quite right (also the reason why there was a restart system in the first place). But I'm still surprised by how it happens (no error given by Qt, just no packets received) and it happens a lot on a server which has tremendous reliable bandwidth but laggy interface. My guess was that the UI and networking were not well separated, but I can't prove that...

Log in to reply