关于QThreadPoolPrivate :: runnableReady的错误?

时间:2017-08-01 08:58:30

标签: qthread

最近我研究QThread源代码,在qthreadpool.cpp文件中,我们可以找到以下代码:

void QThreadPoolThread::run()
{
    QMutexLocker locker(&manager->mutex);
    for(;;) {
        QRunnable *r = runnable;
        runnable = 0;

        do {
            if (r) {
                const bool autoDelete = r->autoDelete();


                // run the task
                locker.unlock();
#ifndef QT_NO_EXCEPTIONS
                try {
#endif
                    r->run();
#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.");
                    registerTheadInactive();
                    throw;
                }
#endif
                locker.relock();

                if (autoDelete && !--r->ref)
                    delete r;
            }

            // if too many threads are active, expire this thread
            if (manager->tooManyThreadsActive())
                break;

            r = !manager->queue.isEmpty() ? manager->queue.takeFirst().first : 0;
        } while (r != 0);

        if (manager->isExiting) {
            registerTheadInactive();
            break;
        }

        // if too many threads are active, expire this thread
        bool expired = manager->tooManyThreadsActive();
        if (!expired) {
            ++manager->waitingThreads;
            registerTheadInactive();
            // wait for work, exiting after the expiry timeout is reached
            expired = !manager->runnableReady.wait(locker.mutex(), manager->expiryTimeout);
            ++manager->activeThreads;

            if (expired)
                --manager->waitingThreads;
        }
        if (expired) {
            manager->expiredThreads.enqueue(this);
            registerTheadInactive();
            break;
        }
    }
}

此代码段表示如果当前任务完成,runnableReady将等待一段时间(默认为30秒),如下所示:

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

在此期间,如果调用了QThreadPoolPrivate :: enqueueTask,则会将新的可运行任务添加到队列中,如下所示:

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

然后,QThreadPoolThread :: run中的runnableReady将被唤醒。但是,正如我们所看到的,QThreadPoolThread类中的成员变量“runnable”为NULL,因此QThreadPoolThread :: run将返回,这不是我们想要的!

在我看来,由于“runnableReady”被唤醒,线程应该在队列中获取新的runnable任务并执行它。通过这种方式,QThreadPool可以重用现有的线程。我错了吗?请帮忙。

0 个答案:

没有答案