Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Offloading a cancelable job to a different thread that needs to update UI

Offloading a cancelable job to a different thread that needs to update UI

Scheduled Pinned Locked Moved Unsolved General and Desktop
4 Posts 2 Posters 364 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    slambert
    wrote on last edited by
    #1

    I want to offload a function to a different thread because it takes a long time to execute and blocks the main thread (and freezes the UI). Here is a simplified version of the code:

    // This function is called when a button is pressed, and it can
    // be called as many times as the user wants. By convention, calling
    // this function while a job is already running will cancel that
    // job and start a new one.
    void Data::RefreshData() {
        if (future.isRunning()) {
            cancelDataGeneration();
            future.waitForFinished();
        }
    
        future = QtConcurrent::run(this, &Data::RegenerateData);
    }
    

    The issue I have is that a part of the work of Data::RegenerateData needs to be ran in the main thread (UI updates and other things). I put the code that need to be executed in the main thread in a different function and the end of Data::RegenerateData emits a signal that triggers this function. However, I now have a different issue: the return of future.waitForFinished() no longer means that the complete job is finished.

    Instead of waiting for future.waitForFinished() to finish, I would like to also wait for the work done in the main thread. I initially tried to achieve this with a QEventLoop that waits for a signal.

    void Data::RefreshData() {
        if (future.isRunning()) {
            cancelDataGeneration();
            future.waitForFinished();
        }
    
        future = QtConcurrent::run(this, &Data::RegenerateData);
    }
    
    // Runs in a worker thread
    void Data::RegenerateData() {
        // Long-running task
    
        // Waiting for the work on the main thread to finish... 
        QEventLoop loop;
        connect(this, SIGNAL(UpdateFinished()), &loop, SLOT(quit()));
        emit Update(); // connected to the OnUpdate slot.
        loop.exec();
    }
    
    void Data::OnUpdate() {
        // Update stuff
    
        emit UpdateFinished();
    }
    

    The problem with this approach is that it will always result in a deadlock. What is wrong with my approach, and how can I achieve what I need?

    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Use a QFutureWatcher to get noticed when the future is done and do the rest of the work in the slot connected to QFutureWatcher::finished()

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      S 1 Reply Last reply
      3
      • Christian EhrlicherC Christian Ehrlicher

        Use a QFutureWatcher to get noticed when the future is done and do the rest of the work in the slot connected to QFutureWatcher::finished()

        S Offline
        S Offline
        slambert
        wrote on last edited by
        #3

        @christian-ehrlicher I don't understand what would be the difference between executing the rest of the work from QFutureWatcher::finished() instead of emitting it from the concurrent task.

        1 Reply Last reply
        0
        • Christian EhrlicherC Offline
          Christian EhrlicherC Offline
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Since there is only one main thread I don't understand your statement here:

          I would like to also wait for the work done in the main thread

          From which thread do you call QtConcurrent::run()? Another one than the main thread?

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved