QThreadPool: obey the docs that say we always use at least 1 thread

Even if the user (usually accidentally) sets a thread count of zero or
negative. The reporter in the bug report did
QThread::idealThreadCount() - 1 on a 1 CPU system...

Drive-by add to the documentation and the missing #include.

Fixes: QTBUG-93007
Change-Id: I6cdea00671e8479b9c50fffd167807d14e030154
Reviewed-by: Samuel Gaist <samuel.gaist@idiap.ch>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
(cherry picked from commit 885eff053797d56f2e295558d0a71b030fbb1a69)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Thiago Macieira 2021-04-21 17:51:01 -07:00 committed by Qt Cherry-pick Bot
parent 25d9bf39d9
commit c0d310d996
3 changed files with 14 additions and 9 deletions

View File

@ -176,7 +176,7 @@ bool QThreadPoolPrivate::tryStart(QRunnable *task)
} }
// can't do anything if we're over the limit // can't do anything if we're over the limit
if (activeThreadCount() >= maxThreadCount) if (activeThreadCount() >= maxThreadCount())
return false; return false;
if (waitingThreads.count() > 0) { if (waitingThreads.count() > 0) {
@ -249,7 +249,7 @@ void QThreadPoolPrivate::tryToStartMoreThreads()
bool QThreadPoolPrivate::tooManyThreadsActive() const bool QThreadPoolPrivate::tooManyThreadsActive() const
{ {
const int activeThreadCount = this->activeThreadCount(); const int activeThreadCount = this->activeThreadCount();
return activeThreadCount > maxThreadCount && (activeThreadCount - reservedThreads) > 1; return activeThreadCount > maxThreadCount() && (activeThreadCount - reservedThreads) > 1;
} }
/*! /*!
@ -571,7 +571,7 @@ bool QThreadPool::tryStart(std::function<void()> functionToRun)
Q_D(QThreadPool); Q_D(QThreadPool);
QMutexLocker locker(&d->mutex); QMutexLocker locker(&d->mutex);
if (!d->allThreads.isEmpty() && d->activeThreadCount() >= d->maxThreadCount) if (!d->allThreads.isEmpty() && d->activeThreadCount() >= d->maxThreadCount())
return false; return false;
QRunnable *runnable = QRunnable::create(std::move(functionToRun)); QRunnable *runnable = QRunnable::create(std::move(functionToRun));
@ -612,7 +612,9 @@ void QThreadPool::setExpiryTimeout(int expiryTimeout)
/*! \property QThreadPool::maxThreadCount /*! \property QThreadPool::maxThreadCount
\brief the maximum number of threads used by the thread pool. \brief the maximum number of threads used by the thread pool. This property
will default to the value of QThread::idealThreadCount() at the moment the
QThreadPool object is created.
\note The thread pool will always use at least 1 thread, even if \note The thread pool will always use at least 1 thread, even if
\a maxThreadCount limit is zero or negative. \a maxThreadCount limit is zero or negative.
@ -623,7 +625,7 @@ void QThreadPool::setExpiryTimeout(int expiryTimeout)
int QThreadPool::maxThreadCount() const int QThreadPool::maxThreadCount() const
{ {
Q_D(const QThreadPool); Q_D(const QThreadPool);
return d->maxThreadCount; return d->requestedMaxThreadCount;
} }
void QThreadPool::setMaxThreadCount(int maxThreadCount) void QThreadPool::setMaxThreadCount(int maxThreadCount)
@ -631,10 +633,10 @@ void QThreadPool::setMaxThreadCount(int maxThreadCount)
Q_D(QThreadPool); Q_D(QThreadPool);
QMutexLocker locker(&d->mutex); QMutexLocker locker(&d->mutex);
if (maxThreadCount == d->maxThreadCount) if (maxThreadCount == d->requestedMaxThreadCount)
return; return;
d->maxThreadCount = maxThreadCount; d->requestedMaxThreadCount = maxThreadCount;
d->tryToStartMoreThreads(); d->tryToStartMoreThreads();
} }

View File

@ -55,6 +55,7 @@
#include "QtCore/qmutex.h" #include "QtCore/qmutex.h"
#include "QtCore/qthread.h" #include "QtCore/qthread.h"
#include "QtCore/qwaitcondition.h" #include "QtCore/qwaitcondition.h"
#include "QtCore/qthreadpool.h"
#include "QtCore/qset.h" #include "QtCore/qset.h"
#include "QtCore/qqueue.h" #include "QtCore/qqueue.h"
#include "private/qobject_p.h" #include "private/qobject_p.h"
@ -158,6 +159,8 @@ public:
void tryToStartMoreThreads(); void tryToStartMoreThreads();
bool tooManyThreadsActive() const; bool tooManyThreadsActive() const;
int maxThreadCount() const
{ return qMax(requestedMaxThreadCount, 1); } // documentation says we start at least one
void startThread(QRunnable *runnable = nullptr); void startThread(QRunnable *runnable = nullptr);
void reset(); void reset();
bool waitForDone(int msecs); bool waitForDone(int msecs);
@ -174,7 +177,7 @@ public:
QWaitCondition noActiveThreads; QWaitCondition noActiveThreads;
int expiryTimeout = 30000; int expiryTimeout = 30000;
int maxThreadCount = QThread::idealThreadCount(); int requestedMaxThreadCount = QThread::idealThreadCount(); // don't use this directly
int reservedThreads = 0; int reservedThreads = 0;
int activeThreads = 0; int activeThreads = 0;
uint stackSize = 0; uint stackSize = 0;

View File

@ -483,7 +483,7 @@ void tst_QThreadPool::setMaxThreadCountStartsAndStopsThreads()
}; };
QThreadPool threadPool; QThreadPool threadPool;
threadPool.setMaxThreadCount(1); threadPool.setMaxThreadCount(-1); // docs say we'll always start at least one
WaitingTask *task = new WaitingTask; WaitingTask *task = new WaitingTask;
threadPool.start(task); threadPool.start(task);