user1389840
user1389840

Reputation: 679

How do I wait for a thread to finish in Qt without blocking its execution?

I have a function that creates a bunch of QThreads to speed up a long calculation, but when I try and sleep until the calculation is done, the background threads never execute for some reason.

I can't figure out why the threads don't execute after I call thread->start(). Here's my code:

multithread.run_multithread(run_function, thread_count);
while(multithread.running)
    QThread::msleep(100);
qDebug() << "done";  // Never reaches this point

And the multithread function:

void Multithread::run_multithread(std::function<void
 (int)>run_function_in, int thread_count) {
    running = true;
    // Create workers and threads
    int thread_idx;
    for(thread_idx=0; thread_idx<thread_count; thread_idx++) {
        ThreadWorker *worker = new ThreadWorker(this, run_function_in);
        QThread *thread = new QThread();
        // Set workers and threads to delete when done
        worker->moveToThread(thread);
        connect(worker, &ThreadWorker::finished, this, &Multithread::check_progress);
        connect(thread, &QThread::started, worker, &ThreadWorker::run);
        connect(worker, &ThreadWorker::finished, thread, &QThread::quit);
        connect(worker, &ThreadWorker::finished, worker, &ThreadWorker::deleteLater);
        connect(thread, &QThread::finished, thread, &QThread::deleteLater);
        // Start thread
        thread->start();
    }
}

running gets set to false in Multithread::check_progress when all the threads finish their part of the calculation. When I remove QThread::msleep(100) the calculation will execute normally, but I need some way to block until it completes.

Upvotes: 0

Views: 3536

Answers (2)

ajshort
ajshort

Reputation: 3754

Rather than using QThread, I would recommend using the Qt Concurrent functionality which provides a higher level of abstraction over the thread primitives. You can use QFutureSynchronizer to wait for several concurrent futures to finish. This object will wait for all attached futures to finish before it allows itself to be destroyed.

An example of how to start several threads and then wait for them all to finish is:

#include <QtConcurrent>

void run_multithread(...) {
  // Set up a new synchronizer.
  QFutureSynchronizer<void> synchronizer;

  // Run n tasks in parallel.
  for (int thread_idx = 0; thread_idx < thread_count; ++thread_idx) {
    synchronizer.addFuture(QtConcurrent::run(run_function_in));
  }

  // The synchroniser will wait for all threads to finish before returning.
}

Upvotes: 1

Orest Hera
Orest Hera

Reputation: 6776

It could be because of optimization, since multithread.running is not changed inside the loop. However, here the main reproducible reason is that the slot Multithread::check_progress is never called by ThreadWorker::finished signals, since the instance of Multithread belongs to your current thread, but the event loop is blocked.

Instead of such sleep you can emit a signal from Multithread object when all threads are finished. Then the computation may be continued from a slot connected to that signal.

Upvotes: 0

Related Questions