Qt World Summit: Register Today!

A bug about QThreadPoolPrivate::runnableReady ?

  • Recently I study QThread source code, in "void QThreadPoolThread::run()" function, we can find below codes:

    void QThreadPoolThread::run()
        QMutexLocker locker(&manager->mutex);
        for(;;) {
            QRunnable *r = runnable;
            runnable = 0;
            do {
                if (r) {
                    const bool autoDelete = r->autoDelete();
                    // run the task
    #ifndef QT_NO_EXCEPTIONS
                    try {
    #ifndef QT_NO_EXCEPTIONS
                    } catch (...) {
                        qWarning("Qt Concurrent has caught an exception thrown from a worker thread.\n"
                                 "This is not supported, exceptions thrown in worker threads must be\n"
                                 "caught before control returns to Qt Concurrent.");
                    if (autoDelete && !--r->ref)
                        delete r;
                // if too many threads are active, expire this thread
                if (manager->tooManyThreadsActive())
                r = !manager->queue.isEmpty() ? manager->queue.takeFirst().first : 0;
            } while (r != 0);
            if (manager->isExiting) {
            // if too many threads are active, expire this thread
            bool expired = manager->tooManyThreadsActive();
            if (!expired) {
                // wait for work, exiting after the expiry timeout is reached
                expired = !manager->runnableReady.wait(locker.mutex(), manager->expiryTimeout);
                if (expired)
            if (expired) {

    This snippet means that if current tasks are finished, runnableReady will wait for some time(30 seconds by default) like below:

    manager->runnableReady.wait(locker.mutex(), manager->expiryTimeout);

    During this period, if QThreadPoolPrivate::enqueueTask is called, a new runnable task will be added to queue like below:

    void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority)
        if (runnable->autoDelete())
        // put it on the queue
        QList<QPair<QRunnable *, int> >::iterator at =
            qUpperBound(queue.begin(), queue.end(), priority);
        queue.insert(at, qMakePair(runnable, priority));

    Then, runnableReady in QThreadPoolThread::run will be waked up. However, as we see, the member variable "runnable" in class QThreadPoolThread is NULL, so QThreadPoolThread::run will return, this is not what we want !

    In my opinion, since "runnableReady" is waked up, the thread should fetch the new runnable task in queue and execute it. In this way, QThreadPool can reuse existing threads. Was I wrong? Please give some help.

  • While there are a few guys here that can look at that, I think you are better of sending your question to the dev mailing list http://lists.qt-project.org/mailman/listinfo/development

  • @julien_lion
    Sorry, I misunderstood the code, it has no bug. Close it now.

Log in to reply