57 QMutexLocker locker(&
manager->mutex);
59 QRunnable *r = runnable;
65 const bool del = r->autoDelete();
69#ifndef QT_NO_EXCEPTIONS
73#ifndef QT_NO_EXCEPTIONS
75 qWarning(
"Qt Concurrent has caught an exception thrown from a worker thread.\n"
76 "This is not supported, exceptions thrown in worker threads must be\n"
77 "caught before control returns to Qt Concurrent.");
89 if (
manager->tooManyThreadsActive())
106 if (!
manager->allThreads.contains(
this)) {
112 if (
manager->tooManyThreadsActive()) {
113 manager->expiredThreads.enqueue(
this);
117 manager->waitingThreads.enqueue(
this);
120 runnableReady.wait(locker.mutex(), QDeadlineTimer(manager->expiryTimeout));
122 if (!
manager->allThreads.contains(
this)) {
123 Q_ASSERT(
manager->queue.isEmpty());
126 if (
manager->waitingThreads.removeOne(
this)) {
127 manager->expiredThreads.enqueue(
this);
147bool QThreadPoolPrivate::tryStart(QRunnable *task)
149 Q_ASSERT(task !=
nullptr);
150 if (allThreads.isEmpty()) {
157 if (areAllThreadsActive())
160 if (!waitingThreads.isEmpty()) {
163 waitingThreads.takeFirst()->runnableReady.wakeOne();
167 if (!expiredThreads.isEmpty()) {
169 QThreadPoolThread *thread = expiredThreads.dequeue();
170 Q_ASSERT(thread->runnable ==
nullptr);
174 thread->runnable = task;
179 Q_ASSERT(thread->isFinished());
180 thread->start(threadPriority);
194void QThreadPoolPrivate::enqueueTask(QRunnable *runnable,
int priority)
196 Q_ASSERT(runnable !=
nullptr);
197 for (QueuePage *page : std::as_const(queue)) {
198 if (page->priority() == priority && !page->isFull()) {
199 page->push(runnable);
203 auto it = std::upper_bound(queue.constBegin(), queue.constEnd(), priority, comparePriority);
204 queue.insert(std::distance(queue.constBegin(), it),
new QueuePage(runnable, priority));
247void QThreadPoolPrivate::startThread(QRunnable *runnable)
249 Q_ASSERT(runnable !=
nullptr);
250 auto thread = std::make_unique<QThreadPoolThread>(
this);
251 if (objectName.isEmpty())
252 objectName = u"Thread (pooled)"_s;
253 thread->setObjectName(objectName);
254 thread->setServiceLevel(serviceLevel);
255 Q_ASSERT(!allThreads.contains(thread.get()));
256 allThreads.insert(thread.get());
259 thread->runnable = runnable;
260 thread.release()->start(threadPriority);
270void QThreadPoolPrivate::reset()
273 auto allThreadsCopy = std::exchange(allThreads, {});
274 expiredThreads.clear();
275 waitingThreads.clear();
279 for (QThreadPoolThread *thread : std::as_const(allThreadsCopy)) {
280 if (thread->isRunning()) {
281 thread->runnableReady.wakeAll();
295bool QThreadPoolPrivate::waitForDone(
const QDeadlineTimer &timer)
297 QMutexLocker locker(&mutex);
298 while (!(queue.isEmpty() && activeThreads == 0) && !timer.hasExpired())
299 noActiveThreads.wait(&mutex, timer);
301 if (!queue.isEmpty() || activeThreads)
345bool QThreadPool::tryTake(QRunnable *runnable)
349 if (runnable ==
nullptr)
352 QMutexLocker locker(&d->mutex);
353 for (QueuePage *page : std::as_const(d->queue)) {
354 if (page->tryTake(runnable)) {
355 if (page->isFinished()) {
356 d->queue.removeOne(page);
442QThreadPool::QThreadPool(QObject *parent)
443 : QObject(*
new QThreadPoolPrivate, parent)
446 connect(
this, &QObject::objectNameChanged,
this, [d](
const QString &newName) {
448 QMutexLocker locker(&d->mutex);
449 d->objectName = newName;
623void QThreadPool::setMaxThreadCount(
int maxThreadCount)
626 QMutexLocker locker(&d->mutex);
628 if (maxThreadCount == d->requestedMaxThreadCount)
631 d->requestedMaxThreadCount = maxThreadCount;
632 d->tryToStartMoreThreads();
799void QThreadPool::startOnReservedThread(QRunnable *runnable)
802 return releaseThread();
805 QMutexLocker locker(&d->mutex);
806 Q_ASSERT(d->reservedThreads > 0);
807 --d->reservedThreads;
809 if (!d->tryStart(runnable)) {
812 d->enqueueTask(runnable, INT_MAX);