Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

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

    General and Desktop
    2
    4
    158
    Loading More Posts
    • 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
      slambert last edited by

      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 Reply Quote 0
      • Christian Ehrlicher
        Christian Ehrlicher Lifetime Qt Champion last edited by

        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 has to stay free or it will die.

        S 1 Reply Last reply Reply Quote 3
        • S
          slambert @Christian Ehrlicher last edited by

          @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 Reply Quote 0
          • Christian Ehrlicher
            Christian Ehrlicher Lifetime Qt Champion last edited by

            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 has to stay free or it will die.

            1 Reply Last reply Reply Quote 0
            • First post
              Last post