Add special thread pool for Qt Gui

To avoid gui slowdowns due to global pool being blocked.

Fixes: QTBUG-109511
Change-Id: I4e8d91e8fb0bd2e395072a082e992a3c5d3464ad
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
(cherry picked from commit 93047c71e8e6dd4ac28e1e59dcb561df11c759eb)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Allan Sandfeld Jensen 2023-02-24 10:57:56 +01:00 committed by Qt Cherry-pick Bot
parent c1c201025e
commit 61b8e334d2
9 changed files with 50 additions and 20 deletions

View File

@ -31,6 +31,7 @@
#include <private/qthread_p.h>
#if QT_CONFIG(thread)
#include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif
#endif
#include <qelapsedtimer.h>
@ -907,8 +908,10 @@ QCoreApplication::~QCoreApplication()
#if QT_CONFIG(thread)
// Synchronize and stop the global thread pool threads.
QThreadPool *globalThreadPool = nullptr;
QThreadPool *guiThreadPool = nullptr;
QT_TRY {
globalThreadPool = QThreadPool::globalInstance();
guiThreadPool = QThreadPoolPrivate::qtGuiInstance();
} QT_CATCH (...) {
// swallow the exception, since destructors shouldn't throw
}
@ -916,6 +919,10 @@ QCoreApplication::~QCoreApplication()
globalThreadPool->waitForDone();
delete globalThreadPool;
}
if (guiThreadPool) {
guiThreadPool->waitForDone();
delete guiThreadPool;
}
#endif
#ifndef QT_NO_QOBJECT

View File

@ -474,6 +474,21 @@ QThreadPool *QThreadPool::globalInstance()
return theInstance;
}
/*!
Returns the QThreadPool instance for Qt Gui.
\internal
*/
QThreadPool *QThreadPoolPrivate::qtGuiInstance()
{
Q_CONSTINIT static QPointer<QThreadPool> guiInstance;
Q_CONSTINIT static QBasicMutex theMutex;
const QMutexLocker locker(&theMutex);
if (guiInstance.isNull() && !QCoreApplication::closingDown())
guiInstance = new QThreadPool();
return guiInstance;
}
/*!
Reserves a thread and uses it to run \a runnable, unless this thread will
make the current thread count exceed maxThreadCount(). In that case,

View File

@ -134,6 +134,8 @@ public:
void stealAndRunRunnable(QRunnable *runnable);
void deletePageIfFinished(QueuePage *page);
static QThreadPool *qtGuiInstance();
mutable QMutex mutex;
QSet<QThreadPoolThread *> allThreads;
QQueue<QThreadPoolThread *> waitingThreads;

View File

@ -35,8 +35,9 @@
#include <private/qfont_p.h>
#if QT_CONFIG(thread)
#include "qsemaphore.h"
#include "qthreadpool.h"
#include <qsemaphore.h>
#include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif
#include <qtgui_tracepoints_p.h>
@ -5119,7 +5120,7 @@ void QImage::applyColorTransform(const QColorTransform &transform)
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
int segments = (qsizetype(width()) * height()) >> 16;
segments = std::min(segments, height());
QThreadPool *threadPool = QThreadPool::globalInstance();
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;

View File

@ -15,6 +15,7 @@
#if QT_CONFIG(thread)
#include <qsemaphore.h>
#include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#ifdef Q_OS_WASM
// WebAssembly has threads; however we can't block the main thread.
#else
@ -203,7 +204,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
int segments = (qsizetype(src->width) * src->height) >> 16;
segments = std::min(segments, src->height);
QThreadPool *threadPool = QThreadPool::globalInstance();
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
return convertSegment(0, src->height);
@ -258,7 +259,7 @@ void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::Ima
int segments = (qsizetype(src->width) * src->height) >> 16;
segments = std::min(segments, src->height);
QThreadPool *threadPool = QThreadPool::globalInstance();
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
return convertSegment(0, src->height);
@ -312,7 +313,7 @@ void convert_generic_over_rgba32f(QImageData *dest, const QImageData *src, Qt::I
int segments = (qsizetype(src->width) * src->height) >> 16;
segments = std::min(segments, src->height);
QThreadPool *threadPool = QThreadPool::globalInstance();
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
return convertSegment(0, src->height);
@ -419,7 +420,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
int segments = (qsizetype(data->width) * data->height) >> 16;
segments = std::min(segments, data->height);
QThreadPool *threadPool = QThreadPool::globalInstance();
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;
@ -513,7 +514,7 @@ bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_for
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
int segments = (qsizetype(data->width) * data->height) >> 16;
segments = std::min(segments, data->height);
QThreadPool *threadPool = QThreadPool::globalInstance();
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;
@ -608,7 +609,7 @@ bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_f
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
int segments = (qsizetype(data->width) * data->height) >> 16;
segments = std::min(segments, data->height);
QThreadPool *threadPool = QThreadPool::globalInstance();
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;

View File

@ -32,6 +32,7 @@
#if defined(QT_USE_THREAD_PARALLEL_FILLS)
#include <qsemaphore.h>
#include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif
QT_BEGIN_NAMESPACE
@ -3777,7 +3778,7 @@ static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP b
#if defined(QT_USE_THREAD_PARALLEL_FILLS)
#define QT_THREAD_PARALLEL_FILLS(function) \
const int segments = (count + 32) / 64; \
QThreadPool *threadPool = QThreadPool::globalInstance(); \
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); \
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { \
QSemaphore semaphore; \
int c = 0; \
@ -3786,7 +3787,7 @@ static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP b
threadPool->start([&, c, cn]() { \
function(c, c + cn); \
semaphore.release(1); \
}); \
}, 1); \
c += cn; \
} \
semaphore.acquire(segments); \

View File

@ -10,8 +10,9 @@
#include "qrgbafloat.h"
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
#include "qsemaphore.h"
#include "qthreadpool.h"
#include <qsemaphore.h>
#include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif
QT_BEGIN_NAMESPACE
@ -273,7 +274,7 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh);
QThreadPool *threadPool = QThreadPool::globalInstance();
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;

View File

@ -6,8 +6,9 @@
#include <private/qsimd_p.h>
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
#include "qsemaphore.h"
#include "qthreadpool.h"
#include <qsemaphore.h>
#include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif
#if defined(__ARM_NEON__)
@ -22,7 +23,7 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh);
QThreadPool *threadPool = QThreadPool::globalInstance();
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;

View File

@ -7,8 +7,9 @@
#include <private/qsimd_p.h>
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
#include "qsemaphore.h"
#include "qthreadpool.h"
#include <qsemaphore.h>
#include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif
#if defined(QT_COMPILER_SUPPORTS_SSE4_1)
@ -23,7 +24,7 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh);
QThreadPool *threadPool = QThreadPool::globalInstance();
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;