c++qtthreadpool

How to run the same QRunnable in a QThreadPool multiple times?


I'm reading the french book "Maîtrisez Qt 5: guide de développement d'applications professionnelles" to learn Qt.

There is a small code in it to explain QThreadPool :

#include "MaTache.h"
#include <QCoreApplication>
#include <QThreadPool>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QThreadPool::globalInstance()->setMaxThreadCount(3);

    for(int i = 0 ; i < 10 ; i++) {
        MaTache *t = new MaTache; // MaTache inherits from QRunnable
        QThreadPool::globalInstance()->start(t);
    }
    
    QThreadPool::globalInstance()->waitForDone();

    return 0;
}

However, I read this advice in the official QT documentation :

Calling QThreadPool::start() multiple times with the same QRunnable when autoDelete is enabled creates a race condition and is not recommended.

Also, I read in the official documentation about QThreadPool::waitForDone(QDeadlineTimer deadline = QDeadlineTimer::Forever) :

Waits until deadline expires for all threads to exit and removes all threads from the thread pool. Returns true if all threads were removed; otherwise it returns false.

So, I have a few questions :

  1. When the advice says "the same QRunnable", is that the same class or the same instance of the class ? Here we use the same class but not the same instance, so is there a race condition ?
  2. If we add t->setAutoDelete(false); (because it is true by default) just before the call to start, how do we manually delete the QRunnable ?
  3. The previous question talks about the deletion of the QRunnable, QThreadPool::waitForDone will rather delete the threads, can I use it indifferently depending on the QRunnable deletion mode?

Solution

  • Here are the three answers, from the comments of the question and this part of the documentation :

    Note that the thread pool takes ownership of the runnable if runnable->autoDelete() returns true, and the runnable will be deleted automatically by the thread pool after the runnable->run() returns. If runnable->autoDelete() returns false, ownership of runnable remains with the caller.

    1. The advice of the documentation, talking about a a race condition when calling QThreadPool::start() multiple times with the same QRunnable (when autoDelete is enabled) is just about the possibility of a double-deletion of the same instance of a QRunnable. In this example we never call QThreadPool::start with the same instance so there is no race condition.

    2. If we add t->setAutoDelete(false); (which is true by default) just before the call to start, we can manually delete the QRunnable after by keeping the adress and calling delete after QThreadPool::globalInstance()->waitForDone();.

    3. Since QThreadPool::waitForDone will rather delete the threads than the QRunnable, it can be used indifferently on the QRunnable deletion mode (with/without auto-delete).