diff --git a/package/freebsd/pkg-plist b/package/freebsd/pkg-plist index e54d8c9f0..bff94df2d 100644 --- a/package/freebsd/pkg-plist +++ b/package/freebsd/pkg-plist @@ -108,7 +108,6 @@ include/katie/QtCore/QRect include/katie/QtCore/QRectF include/katie/QtCore/QRegExp include/katie/QtCore/QReturnArgument -include/katie/QtCore/QRunnable include/katie/QtCore/QScopedPointer include/katie/QtCore/QScopedPointerPodDeleter include/katie/QtCore/QScopedValueRollback @@ -136,7 +135,6 @@ include/katie/QtCore/QTextConverter include/katie/QtCore/QTextStream include/katie/QtCore/QTextStreamFunction include/katie/QtCore/QThread -include/katie/QtCore/QThreadPool include/katie/QtCore/QTime include/katie/QtCore/QTimeLine include/katie/QtCore/QTimer @@ -226,7 +224,6 @@ include/katie/QtCore/qprocess.h include/katie/QtCore/qqueue.h include/katie/QtCore/qrect.h include/katie/QtCore/qregexp.h -include/katie/QtCore/qrunnable.h include/katie/QtCore/qscopedpointer.h include/katie/QtCore/qscopedvaluerollback.h include/katie/QtCore/qsemaphore.h @@ -246,7 +243,6 @@ include/katie/QtCore/qtemporaryfile.h include/katie/QtCore/qtextcodec.h include/katie/QtCore/qtextstream.h include/katie/QtCore/qthread.h -include/katie/QtCore/qthreadpool.h include/katie/QtCore/qtimeline.h include/katie/QtCore/qtimer.h include/katie/QtCore/qtranslator.h diff --git a/scripts/namefsck.py b/scripts/namefsck.py index ecf55d719..ea6ec9374 100755 --- a/scripts/namefsck.py +++ b/scripts/namefsck.py @@ -350,7 +350,6 @@ classlist = [ "QReturnArgument", "QRgb", "QRubberBand", - "QRunnable", "QScopedPointer", "QScopedPointerPodDeleter", "QScopedValueRollback", @@ -493,7 +492,6 @@ classlist = [ "QTextTableCellFormat", "QTextTableFormat", "QThread", - "QThreadPool", "QTileRules", "QTime", "QTimeEdit", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 79051d0d2..033398532 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -28,7 +28,6 @@ set(CORE_PUBLIC_HEADERS QDebug QFileInfo QDateTime - QThreadPool QSettings QStandardPaths QPlugin @@ -74,7 +73,6 @@ set(CORE_PUBLIC_HEADERS QFile QCache QAbstractEventDispatcher - QRunnable QTimeLine QTextCodec QStringList @@ -170,9 +168,6 @@ set(CORE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/thread/qmutexpool_p.h ${CMAKE_CURRENT_SOURCE_DIR}/thread/qorderedmutexlocker_p.h ${CMAKE_CURRENT_SOURCE_DIR}/thread/qthread_p.h - ${CMAKE_CURRENT_SOURCE_DIR}/thread/qrunnable.h - ${CMAKE_CURRENT_SOURCE_DIR}/thread/qthreadpool.h - ${CMAKE_CURRENT_SOURCE_DIR}/thread/qthreadpool_p.h ${CMAKE_CURRENT_SOURCE_DIR}/tools/qalgorithms.h ${CMAKE_CURRENT_SOURCE_DIR}/tools/qbitarray.h ${CMAKE_CURRENT_SOURCE_DIR}/tools/qbytearray.h @@ -270,10 +265,8 @@ set(CORE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/plugin/qlibrary_unix.cpp ${CMAKE_CURRENT_SOURCE_DIR}/thread/qatomic.cpp ${CMAKE_CURRENT_SOURCE_DIR}/thread/qmutex.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/thread/qrunnable.cpp ${CMAKE_CURRENT_SOURCE_DIR}/thread/qsemaphore.cpp ${CMAKE_CURRENT_SOURCE_DIR}/thread/qthread.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/thread/qthreadpool.cpp ${CMAKE_CURRENT_SOURCE_DIR}/thread/qthread_unix.cpp ${CMAKE_CURRENT_SOURCE_DIR}/thread/qwaitcondition_unix.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tools/qbitarray.cpp diff --git a/src/core/kernel/qcoreapplication.cpp b/src/core/kernel/qcoreapplication.cpp index 02d859de5..b8820162a 100644 --- a/src/core/kernel/qcoreapplication.cpp +++ b/src/core/kernel/qcoreapplication.cpp @@ -33,7 +33,6 @@ #include "qhash.h" #include "qtextcodec.h" #include "qthread.h" -#include "qthreadpool.h" #include "qstandardpaths.h" #include "qelapsedtimer.h" #include "qscopedpointer.h" @@ -361,13 +360,6 @@ QCoreApplication::~QCoreApplication() QCoreApplicationPrivate::is_app_closing = true; QCoreApplicationPrivate::is_app_running = false; -#if !defined(QT_NO_THREAD) - // Synchronize and stop the global thread pool threads. - QThreadPool *globalThreadPool = QThreadPool::globalInstance(); - if (globalThreadPool) - globalThreadPool->waitForDone(); -#endif - #ifndef QT_NO_LIBRARY coreappdata()->app_librarypaths.clear(); coreappdata()->app_pluginpaths.clear(); diff --git a/src/core/thread/qrunnable.cpp b/src/core/thread/qrunnable.cpp deleted file mode 100644 index 737432dc3..000000000 --- a/src/core/thread/qrunnable.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the QtCore module of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \class QRunnable - \since 4.4 - \brief The QRunnable class is the base class for all runnable objects. - - \ingroup thread - - The QRunnable class is an interface for representing a task or - piece of code that needs to be executed, represented by your - reimplementation of the run() function. - - You can use QThreadPool to execute your code in a separate - thread. QThreadPool deletes the QRunnable automatically if - autoDelete() returns true (the default). Use setAutoDelete() to - change the auto-deletion flag. - - QThreadPool supports executing the same QRunnable more than once - by calling QThreadPool::tryStart(this) from within the run() function. - If autoDelete is enabled the QRunnable will be deleted when - the last thread exits the run function. Calling QThreadPool::start() - multiple times with the same QRunnable when autoDelete is enabled - creates a race condition and is not recommended. - - \sa QThreadPool -*/ - -/*! \fn QRunnable::run() - Implement this pure virtual function in your subclass. -*/ - -/*! \fn QRunnable::QRunnable() - Constructs a QRunnable. Auto-deletion is enabled by default. - - \sa autoDelete(), setAutoDelete() -*/ - -/*! \fn QRunnable::~QRunnable() - QRunnable virtual destructor. -*/ - -/*! \fn bool QRunnable::autoDelete() const - - Returns true is auto-deletion is enabled; false otherwise. - - If auto-deletion is enabled, QThreadPool will automatically delete - this runnable after calling run(); otherwise, ownership remains - with the application programmer. - - \sa setAutoDelete(), QThreadPool -*/ - -/*! \fn bool QRunnable::setAutoDelete(bool autoDelete) - - Enables auto-deletion if \a autoDelete is true; otherwise - auto-deletion is disabled. - - If auto-deletion is enabled, QThreadPool will automatically delete - this runnable after calling run(); otherwise, ownership remains - with the application programmer. - - Note that this flag must be set before calling - QThreadPool::start(). Calling this function after - QThreadPool::start() results in undefined behavior. - - \sa autoDelete(), QThreadPool -*/ diff --git a/src/core/thread/qrunnable.h b/src/core/thread/qrunnable.h deleted file mode 100644 index b51ebc3ac..000000000 --- a/src/core/thread/qrunnable.h +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the QtCore module of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QRUNNABLE_H -#define QRUNNABLE_H - -#include - -QT_BEGIN_NAMESPACE - - -class QRunnable -{ -public: - virtual void run() = 0; - - QRunnable() : ref(0) { } - virtual ~QRunnable() { } - - bool autoDelete() const { return ref != -1; } - void setAutoDelete(bool _autoDelete) { ref = _autoDelete ? 0 : -1; } - -private: - int ref; - - friend class QThreadPoolPrivate; - friend class QThreadPoolThread; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/core/thread/qthreadpool.cpp b/src/core/thread/qthreadpool.cpp deleted file mode 100644 index c04580175..000000000 --- a/src/core/thread/qthreadpool.cpp +++ /dev/null @@ -1,573 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the QtCore module of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qthreadpool.h" -#include "qthreadpool_p.h" -#include "qelapsedtimer.h" -#include "qscopedpointer.h" - -#ifndef QT_NO_THREAD - -QT_BEGIN_NAMESPACE - -inline bool operator<(int priority, const QPair &p) -{ - return p.second < priority; -} - -inline bool operator<(const QPair &p, int priority) -{ - return priority < p.second; -} - -Q_GLOBAL_STATIC(QThreadPool, theInstance) - -/* - QThread wrapper, provides synchronization against a ThreadPool -*/ -class QThreadPoolThread : public QThread -{ -public: - QThreadPoolThread(QThreadPoolPrivate *manager); - void run() final; - void registerThreadInactive(); - - QWaitCondition runnableReady; - QThreadPoolPrivate *manager; - QRunnable *runnable; -}; - -/* - QThreadPool private class. -*/ -QThreadPoolThread::QThreadPoolThread(QThreadPoolPrivate *manager) - : manager(manager), - runnable(nullptr) -{ -} - -void QThreadPoolThread::run() -{ - QMutexLocker locker(&manager->mutex); - for(;;) { - QRunnable *r = runnable; - runnable = nullptr; - - do { - if (r) { - const bool autoDelete = r->autoDelete(); - - // run the task - locker.unlock(); - QT_TRY { - r->run(); - } QT_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."); - registerThreadInactive(); - QT_RETHROW; - } - 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 : nullptr; - } while (r != nullptr); - - if (manager->isExiting) { - registerThreadInactive(); - break; - } - - // if too many threads are active, expire this thread - bool expired = manager->tooManyThreadsActive(); - if (!expired) { - manager->waitingThreads.enqueue(this); - registerThreadInactive(); - // wait for work, exiting after the expiry timeout is reached - runnableReady.wait(locker.mutex(), manager->expiryTimeout); - ++manager->activeThreads; - if (manager->waitingThreads.removeOne(this)) { - expired = true; - } - } - if (expired) { - manager->expiredThreads.enqueue(this); - registerThreadInactive(); - break; - } - } -} - -void QThreadPoolThread::registerThreadInactive() -{ - if (--manager->activeThreads == 0) { - manager->noActiveThreads.wakeAll(); - } -} - - -/* \internal - -*/ -QThreadPoolPrivate:: QThreadPoolPrivate() - : isExiting(false), - expiryTimeout(30000), - maxThreadCount(qAbs(QThread::idealThreadCount())), - reservedThreads(0), - activeThreads(0) -{ -} - -bool QThreadPoolPrivate::tryStart(QRunnable *task) -{ - if (allThreads.isEmpty()) { - // always create at least one thread - startThread(task); - return true; - } - - // can't do anything if we're over the limit - if (activeThreadCount() >= maxThreadCount) { - return false; - } - - if (waitingThreads.count() > 0) { - // recycle an available thread - enqueueTask(task); - waitingThreads.takeFirst()->runnableReady.wakeOne(); - return true; - } - - if (!expiredThreads.isEmpty()) { - // restart an expired thread - QThreadPoolThread *thread = expiredThreads.dequeue(); - Q_ASSERT(thread->runnable == nullptr); - - ++activeThreads; - - if (task->autoDelete()) - ++task->ref; - thread->runnable = task; - thread->start(); - return true; - } - - // start a new thread - startThread(task); - return true; -} - -void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority) -{ - if (runnable->autoDelete()) { - ++runnable->ref; - } - - // put it on the queue - QList >::iterator at = qUpperBound(queue.begin(), queue.end(), priority); - queue.insert(at, qMakePair(runnable, priority)); -} - -int QThreadPoolPrivate::activeThreadCount() const -{ - return (allThreads.count() - expiredThreads.count() - waitingThreads.count() + reservedThreads); -} - -void QThreadPoolPrivate::tryToStartMoreThreads() -{ - // try to push tasks on the queue to any available threads - while (!queue.isEmpty() && tryStart(queue.first().first)) { - queue.removeFirst(); - } -} - -bool QThreadPoolPrivate::tooManyThreadsActive() const -{ - const int activeThreadCount = this->activeThreadCount(); - return activeThreadCount > maxThreadCount && (activeThreadCount - reservedThreads) > 1; -} - -/*! - \internal -*/ -void QThreadPoolPrivate::startThread(QRunnable *runnable) -{ - QScopedPointer thread(new QThreadPoolThread(this)); - thread->setObjectName(QLatin1String("Thread (pooled)")); - allThreads.insert(thread.data()); - ++activeThreads; - - if (runnable->autoDelete()) { - ++runnable->ref; - } - thread->runnable = runnable; - thread.take()->start(); -} - -/*! - \internal - Makes all threads exit, waits for each thread to exit and deletes it. -*/ -void QThreadPoolPrivate::reset() -{ - QMutexLocker locker(&mutex); - isExiting = true; - - do { - // make a copy of the set so that we can iterate without the lock - QSet allThreadsCopy = allThreads; - allThreads.clear(); - locker.unlock(); - - foreach (QThreadPoolThread *thread, allThreadsCopy) { - thread->runnableReady.wakeAll(); - thread->wait(); - delete thread; - } - - locker.relock(); - // repeat until all newly arrived threads have also completed - } while (!allThreads.isEmpty()); - - waitingThreads.clear(); - expiredThreads.clear(); - - isExiting = false; -} - -bool QThreadPoolPrivate::waitForDone(int msecs) -{ - QMutexLocker locker(&mutex); - if (msecs < 0) { - if (!queue.isEmpty() || activeThreads != 0) { - noActiveThreads.wait(locker.mutex()); - } - } else { - if (!queue.isEmpty() || activeThreads != 0) { - noActiveThreads.wait(locker.mutex(), msecs); - } - } - return (queue.isEmpty() && activeThreads == 0); -} - -/*! - \class QThreadPool - \brief The QThreadPool class manages a collection of QThreads. - \since 4.4 - \threadsafe - - \ingroup thread - - QThreadPool manages and recyles individual QThread objects to help reduce - thread creation costs in programs that use threads. Each Qt application - has one global QThreadPool object, which can be accessed by calling - globalInstance(). - - To use one of the QThreadPool threads, subclass QRunnable and implement - the run() virtual function. Then create an object of that class and pass - it to QThreadPool::start(). - - \snippet doc/src/snippets/code/src_corelib_concurrent_qthreadpool.cpp 0 - - QThreadPool deletes the QRunnable automatically by default. Use - QRunnable::setAutoDelete() to change the auto-deletion flag. - - QThreadPool supports executing the same QRunnable more than once - by calling tryStart(this) from within QRunnable::run(). - If autoDelete is enabled the QRunnable will be deleted when - the last thread exits the run function. Calling start() - multiple times with the same QRunnable when autoDelete is enabled - creates a race condition and is not recommended. - - Threads that are unused for a certain amount of time will expire. The - default expiry timeout is 30000 milliseconds (30 seconds). This can be - changed using setExpiryTimeout(). Setting a negative expiry timeout - disables the expiry mechanism. - - Call maxThreadCount() to query the maximum number of threads to be used. - If needed, you can change the limit with setMaxThreadCount(). The default - maxThreadCount() is QThread::idealThreadCount(). The activeThreadCount() - function returns the number of threads currently doing work. - - The reserveThread() function reserves a thread for external - use. Use releaseThread() when your are done with the thread, so - that it may be reused. Essentially, these functions temporarily - increase or reduce the active thread count and are useful when - implementing time-consuming operations that are not visible to the - QThreadPool. - - Note that QThreadPool is a low-level class for managing threads, see - QtConcurrent::run() or the other - \l {Concurrent Programming}{Qt Concurrent} APIs for higher - level alternatives. - - \sa QRunnable -*/ - -/*! - Constructs a thread pool with the given \a parent. -*/ -QThreadPool::QThreadPool(QObject *parent) - : QObject(*new QThreadPoolPrivate, parent) -{ -} - -/*! - Destroys the QThreadPool. - This function will block until all runnables have been completed. -*/ -QThreadPool::~QThreadPool() -{ - waitForDone(); -} - -/*! - Returns the global QThreadPool instance. -*/ -QThreadPool *QThreadPool::globalInstance() -{ - return theInstance(); -} - -/*! - Reserves a thread and uses it to run \a runnable, unless this thread will - make the current thread count exceed maxThreadCount(). In that case, - \a runnable is added to a run queue instead. The \a priority argument can - be used to control the run queue's order of execution. - - Note that the thread pool takes ownership of the \a runnable if - \l{QRunnable::autoDelete()}{runnable->autoDelete()} returns true, - and the \a runnable will be deleted automatically by the thread - pool after the \l{QRunnable::run()}{runnable->run()} returns. If - \l{QRunnable::autoDelete()}{runnable->autoDelete()} returns false, - ownership of \a runnable remains with the caller. Note that - changing the auto-deletion on \a runnable after calling this - functions results in undefined behavior. -*/ -void QThreadPool::start(QRunnable *runnable, int priority) -{ - if (Q_UNLIKELY(!runnable)) { - return; - } - - Q_D(QThreadPool); - QMutexLocker locker(&d->mutex); - - if (!d->tryStart(runnable)) { - d->enqueueTask(runnable, priority); - - if (!d->waitingThreads.isEmpty()) { - d->waitingThreads.takeFirst()->runnableReady.wakeOne(); - } - } -} - -/*! - Attempts to reserve a thread to run \a runnable. - - If no threads are available at the time of calling, then this function - does nothing and returns false. Otherwise, \a runnable is run immediately - using one available thread and this function returns true. - - Note that the thread pool takes ownership of the \a runnable if - \l{QRunnable::autoDelete()}{runnable->autoDelete()} returns true, - and the \a runnable will be deleted automatically by the thread - pool after the \l{QRunnable::run()}{runnable->run()} returns. If - \l{QRunnable::autoDelete()}{runnable->autoDelete()} returns false, - ownership of \a runnable remains with the caller. Note that - changing the auto-deletion on \a runnable after calling this - function results in undefined behavior. -*/ -bool QThreadPool::tryStart(QRunnable *runnable) -{ - if (Q_UNLIKELY(!runnable)) { - return false; - } - - Q_D(QThreadPool); - QMutexLocker locker(&d->mutex); - - if (d->allThreads.isEmpty() == false && d->activeThreadCount() >= d->maxThreadCount) { - return false; - } - - return d->tryStart(runnable); -} - -/*! - \property QThreadPool::expiryTimeout - - Threads that are unused for \a expiryTimeout milliseconds are considered - to have expired and will exit. Such threads will be restarted as needed. - The default \a expiryTimeout is 30000 milliseconds (30 seconds). If - \a expiryTimeout is negative, newly created threads will not expire, e.g., - they will not exit until the thread pool is destroyed. - - Note that setting \a expiryTimeout has no effect on already running - threads. Only newly created threads will use the new \a expiryTimeout. - We recommend setting the \a expiryTimeout immediately after creating the - thread pool, but before calling start(). -*/ -int QThreadPool::expiryTimeout() const -{ - Q_D(const QThreadPool); - return d->expiryTimeout; -} - -void QThreadPool::setExpiryTimeout(int expiryTimeout) -{ - Q_D(QThreadPool); - QMutexLocker locker(&d->mutex); - - if (d->expiryTimeout == expiryTimeout) { - return; - } - d->expiryTimeout = expiryTimeout; -} - -/*! - \property QThreadPool::maxThreadCount - - This property represents the maximum number of threads used by the thread - pool. - - \note The thread pool will always use at least 1 thread, even if - \a maxThreadCount limit is zero or negative. - - The default \a maxThreadCount is QThread::idealThreadCount(). -*/ -int QThreadPool::maxThreadCount() const -{ - Q_D(const QThreadPool); - return d->maxThreadCount; -} - -void QThreadPool::setMaxThreadCount(int maxThreadCount) -{ - Q_D(QThreadPool); - QMutexLocker locker(&d->mutex); - - if (maxThreadCount == d->maxThreadCount) { - return; - } - - d->maxThreadCount = maxThreadCount; - d->tryToStartMoreThreads(); -} - -/*! - \property QThreadPool::activeThreadCount - - This property represents the number of active threads in the thread pool. - - \note It is possible for this function to return a value that is greater - than maxThreadCount(). See reserveThread() for more details. - - \sa reserveThread(), releaseThread() -*/ -int QThreadPool::activeThreadCount() const -{ - Q_D(const QThreadPool); - return d->activeThreadCount(); -} - -/*! - Reserves one thread, disregarding activeThreadCount() and maxThreadCount(). - - Once you are done with the thread, call releaseThread() to allow it to be - reused. - - \note This function will always increase the number of active threads. - This means that by using this function, it is possible for - activeThreadCount() to return a value greater than maxThreadCount() . - - \sa releaseThread() -*/ -void QThreadPool::reserveThread() -{ - Q_D(QThreadPool); - QMutexLocker locker(&d->mutex); - ++d->reservedThreads; -} - -/*! - Releases a thread previously reserved by a call to reserveThread(). - - \note Calling this function without previously reserving a thread - temporarily increases maxThreadCount(). This is useful when a - thread goes to sleep waiting for more work, allowing other threads - to continue. Be sure to call reserveThread() when done waiting, so - that the thread pool can correctly maintain the - activeThreadCount(). - - \sa reserveThread() -*/ -void QThreadPool::releaseThread() -{ - Q_D(QThreadPool); - QMutexLocker locker(&d->mutex); - --d->reservedThreads; - d->tryToStartMoreThreads(); -} - -/*! - Waits for each thread to exit and removes all threads from the thread pool. -*/ -void QThreadPool::waitForDone() -{ - Q_D(QThreadPool); - d->waitForDone(); - d->reset(); -} - -/*! - \overload waitForDone() - \since 4.8 - - Waits up to \a msecs milliseconds for all threads to exit and removes all - threads from the thread pool. Returns true if all threads were removed; - otherwise it returns false. -*/ -bool QThreadPool::waitForDone(int msecs) -{ - Q_D(QThreadPool); - const bool rc = d->waitForDone(msecs); - if (rc) { - d->reset(); - } - return rc; -} - -#include "moc_qthreadpool.h" - -QT_END_NAMESPACE - -#endif diff --git a/src/core/thread/qthreadpool.h b/src/core/thread/qthreadpool.h deleted file mode 100644 index ad8d95a19..000000000 --- a/src/core/thread/qthreadpool.h +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the QtCore module of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTHREADPOOL_H -#define QTHREADPOOL_H - -#include -#include - -#ifndef QT_NO_THREAD - -QT_BEGIN_NAMESPACE - -class QThreadPoolPrivate; -class Q_CORE_EXPORT QThreadPool : public QObject -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QThreadPool) - Q_PROPERTY(int expiryTimeout READ expiryTimeout WRITE setExpiryTimeout) - Q_PROPERTY(int maxThreadCount READ maxThreadCount WRITE setMaxThreadCount) - Q_PROPERTY(int activeThreadCount READ activeThreadCount) - -public: - QThreadPool(QObject *parent = nullptr); - ~QThreadPool(); - - static QThreadPool *globalInstance(); - - void start(QRunnable *runnable, int priority = 0); - bool tryStart(QRunnable *runnable); - - int expiryTimeout() const; - void setExpiryTimeout(int expiryTimeout); - - int maxThreadCount() const; - void setMaxThreadCount(int maxThreadCount); - - int activeThreadCount() const; - - void reserveThread(); - void releaseThread(); - - void waitForDone(); - bool waitForDone(int msecs); -}; - -QT_END_NAMESPACE - -#endif // QT_NO_THREAD - -#endif diff --git a/src/core/thread/qthreadpool_p.h b/src/core/thread/qthreadpool_p.h deleted file mode 100644 index 54c2f191c..000000000 --- a/src/core/thread/qthreadpool_p.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the QtCore module of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTHREADPOOL_P_H -#define QTHREADPOOL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Katie API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// -// - -#include "QtCore/qmutex.h" -#include "QtCore/qwaitcondition.h" -#include "QtCore/qset.h" -#include "QtCore/qqueue.h" -#include "qobject_p.h" - -#ifndef QT_NO_THREAD - -QT_BEGIN_NAMESPACE - -class QThreadPoolThread; -class QThreadPoolPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QThreadPool) - friend class QThreadPoolThread; - -public: - QThreadPoolPrivate(); - - bool tryStart(QRunnable *task); - void enqueueTask(QRunnable *task, int priority = 0); - int activeThreadCount() const; - - void tryToStartMoreThreads(); - bool tooManyThreadsActive() const; - - void startThread(QRunnable *runnable); - void reset(); - bool waitForDone(int msecs = -1); - - QMutex mutex; - QSet allThreads; - QQueue waitingThreads; - QQueue expiredThreads; - QList > queue; - QWaitCondition noActiveThreads; - - bool isExiting; - int expiryTimeout; - int maxThreadCount; - int reservedThreads; - int activeThreads; -}; - -QT_END_NAMESPACE - -#endif // QT_NO_THREAD -#endif diff --git a/src/tools/uic/cpp/cppwriteincludes.cpp b/src/tools/uic/cpp/cppwriteincludes.cpp index 5d0ebe245..4f0309c14 100644 --- a/src/tools/uic/cpp/cppwriteincludes.cpp +++ b/src/tools/uic/cpp/cppwriteincludes.cpp @@ -477,7 +477,6 @@ static const struct ClassTblData { { QLatin1String("QTextTableCellFormat"), QLatin1String("QtGui/qtextformat.h") }, { QLatin1String("QTextTableFormat"), QLatin1String("QtGui/qtextformat.h") }, { QLatin1String("QThread"), QLatin1String("QtCore/qthread.h") }, - { QLatin1String("QThreadPool"), QLatin1String("QtCore/qthreadpool.h") }, { QLatin1String("QTime"), QLatin1String("QtCore/qdatetime.h") }, { QLatin1String("QTimeEdit"), QLatin1String("QtGui/qdatetimeedit.h") }, { QLatin1String("QTimeLine"), QLatin1String("QtCore/qtimeline.h") }, diff --git a/tests/auto/qthreadpool/CMakeLists.txt b/tests/auto/qthreadpool/CMakeLists.txt deleted file mode 100644 index 9d8d18d5f..000000000 --- a/tests/auto/qthreadpool/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -katie_test(tst_qthreadpool - ${CMAKE_CURRENT_SOURCE_DIR}/tst_qthreadpool.cpp -) diff --git a/tests/auto/qthreadpool/tst_qthreadpool.cpp b/tests/auto/qthreadpool/tst_qthreadpool.cpp deleted file mode 100644 index cb5e57159..000000000 --- a/tests/auto/qthreadpool/tst_qthreadpool.cpp +++ /dev/null @@ -1,948 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the test suite of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include -#include -#include - -#include "../../shared/util.h" - -typedef void (*FunctionPointer)(); - -class FunctionPointerTask : public QRunnable -{ -public: - FunctionPointerTask(FunctionPointer function) - :function(function) {} - void run() { function(); } -private: - FunctionPointer function; -}; - -QRunnable *createTask(FunctionPointer pointer) -{ - return new FunctionPointerTask(pointer); -} - -class tst_QThreadPool : public QObject -{ - Q_OBJECT -public: - tst_QThreadPool(); - ~tst_QThreadPool(); - - static QMutex *functionTestMutex; - -private slots: - void runFunction(); - void createThreadRunFunction(); - void runMultiple(); - void waitcomplete(); - void runTask(); - void singleton(); - void destruction(); - void threadRecycling(); - void expiryTimeout(); - void expiryTimeoutRace(); - void exceptions(); - void maxThreadCount(); - void setMaxThreadCount_data(); - void setMaxThreadCount(); - void setMaxThreadCountStartsAndStopsThreads(); - void activeThreadCount(); - void reserveThread_data(); - void reserveThread(); - void releaseThread_data(); - void releaseThread(); - void reserveAndStart(); - void start(); - void tryStart(); - void tryStartPeakThreadCount(); - void tryStartCount(); - void waitForDone(); - void waitForDoneTimeout(); - void destroyingWaitsForTasksToFinish(); - void stressTest(); - -private: - QMutex m_functionTestMutex; -}; - - -QMutex *tst_QThreadPool::functionTestMutex = 0; - -tst_QThreadPool::tst_QThreadPool() -{ - tst_QThreadPool::functionTestMutex = &m_functionTestMutex; -} - -tst_QThreadPool::~tst_QThreadPool() -{ - tst_QThreadPool::functionTestMutex = 0; -} - -int testFunctionCount; - -void sleepTestFunction() -{ - QTest::qSleep(1000); - ++testFunctionCount; -} - -void emptyFunct() -{ - -} - -void noSleepTestFunction() -{ - ++testFunctionCount; -} - -void sleepTestFunctionMutex() -{ - Q_ASSERT(tst_QThreadPool::functionTestMutex); - QTest::qSleep(1000); - tst_QThreadPool::functionTestMutex->lock(); - ++testFunctionCount; - tst_QThreadPool::functionTestMutex->unlock(); -} - -void noSleepTestFunctionMutex() -{ - Q_ASSERT(tst_QThreadPool::functionTestMutex); - tst_QThreadPool::functionTestMutex->lock(); - ++testFunctionCount; - tst_QThreadPool::functionTestMutex->unlock(); -} - -void tst_QThreadPool::runFunction() -{ - { - QThreadPool manager; - testFunctionCount = 0; - manager.start(createTask(noSleepTestFunction)); - } - QCOMPARE(testFunctionCount, 1); -} - -void tst_QThreadPool::createThreadRunFunction() -{ - { - QThreadPool manager; - testFunctionCount = 0; - manager.start(createTask(noSleepTestFunction)); - } - - QCOMPARE(testFunctionCount, 1); -} - -void tst_QThreadPool::runMultiple() -{ - const int runs = 10; - - { - QThreadPool manager; - testFunctionCount = 0; - for (int i = 0; i < runs; ++i) { - manager.start(createTask(sleepTestFunctionMutex)); - } - } - QCOMPARE(testFunctionCount, runs); - - { - QThreadPool manager; - testFunctionCount = 0; - for (int i = 0; i < runs; ++i) { - manager.start(createTask(noSleepTestFunctionMutex)); - } - } - QCOMPARE(testFunctionCount, runs); - - { - QThreadPool manager; - for (int i = 0; i < 500; ++i) - manager.start(createTask(emptyFunct)); - } -} - -void tst_QThreadPool::waitcomplete() -{ - testFunctionCount = 0; - const int runs = 500; - for (int i = 0; i < 500; ++i) { - QThreadPool pool; - pool.start(createTask(noSleepTestFunction)); - } - QCOMPARE(testFunctionCount, runs); -} - -QAtomicInt ran(0); // bool -class TestTask : public QRunnable -{ -public: - void run() - { - ran = 1; - } -}; - -void tst_QThreadPool::runTask() -{ - QThreadPool manager; - ran = 0; - manager.start(new TestTask()); - // Hang if task is not runned. - while (ran == 0) - QTest::qSleep(100); // no busy loop - this doesn't work with FIFO schedulers -} - -/* - Test running via QThreadPool::globalInstance() -*/ -void tst_QThreadPool::singleton() -{ - ran = 0; - QThreadPool::globalInstance()->start(new TestTask()); - while (ran == 0) - QTest::qSleep(100); // no busy loop - this doesn't work with FIFO schedulers -} - -QAtomicInt *value = 0; -class IntAccessor : public QRunnable -{ -public: - void run() - { - for (int i = 0; i < 100; ++i) { - value->ref(); - QTest::qSleep(1); - } - } -}; - -/* - Test that the ThreadManager destructor waits until - all threads have completed. -*/ -void tst_QThreadPool::destruction() -{ - value = new QAtomicInt(0); - QThreadPool *threadManager = new QThreadPool(); - threadManager->start(new IntAccessor()); - threadManager->start(new IntAccessor()); - delete threadManager; - delete value; -} - -QSemaphore threadRecyclingSemaphore; -QThread *recycledThread = 0; - -class ThreadRecorderTask : public QRunnable -{ -public: - void run() - { - recycledThread = QThread::currentThread(); - threadRecyclingSemaphore.release(); - } -}; - -/* - Test that the thread pool really reuses threads. -*/ -void tst_QThreadPool::threadRecycling() -{ - QThreadPool threadPool; - - threadPool.start(new ThreadRecorderTask()); - threadRecyclingSemaphore.acquire(); - QThread *thread1 = recycledThread; - - QTest::qSleep(100); - - threadPool.start(new ThreadRecorderTask()); - threadRecyclingSemaphore.acquire(); - QThread *thread2 = recycledThread; - QCOMPARE(thread1, thread2); - - QTest::qSleep(100); - - threadPool.start(new ThreadRecorderTask()); - threadRecyclingSemaphore.acquire(); - QThread *thread3 = recycledThread; - QCOMPARE(thread2, thread3); -} - -class ExpiryTimeoutTask : public QRunnable -{ -public: - QThread *thread; - QAtomicInt runCount; - QSemaphore semaphore; - - ExpiryTimeoutTask() - : thread(0), runCount(0) - { - setAutoDelete(false); - } - - void run() - { - thread = QThread::currentThread(); - runCount.ref(); - semaphore.release(); - } -}; - -void tst_QThreadPool::expiryTimeout() -{ - ExpiryTimeoutTask task; - - QThreadPool threadPool; - threadPool.setMaxThreadCount(1); - - int expiryTimeout = threadPool.expiryTimeout(); - threadPool.setExpiryTimeout(1000); - QCOMPARE(threadPool.expiryTimeout(), 1000); - - // run the task - threadPool.start(&task); - QVERIFY(task.semaphore.tryAcquire(1, 10000)); - QCOMPARE(int(task.runCount), 1); - QVERIFY(!task.thread->wait(100)); - // thread should expire - QThread *firstThread = task.thread; - QVERIFY(task.thread->wait(10000)); - - // run task again, thread should be restarted - threadPool.start(&task); - QVERIFY(task.semaphore.tryAcquire(1, 10000)); - QCOMPARE(int(task.runCount), 2); - QVERIFY(!task.thread->wait(100)); - // thread should expire again - QVERIFY(task.thread->wait(10000)); - - // thread pool should have reused the expired thread (instead of - // starting a new one) - QCOMPARE(firstThread, task.thread); - - threadPool.setExpiryTimeout(expiryTimeout); - QCOMPARE(threadPool.expiryTimeout(), expiryTimeout); -} - -void tst_QThreadPool::expiryTimeoutRace() // QTBUG-3786 -{ - ExpiryTimeoutTask task; - - QThreadPool threadPool; - threadPool.setMaxThreadCount(1); - threadPool.setExpiryTimeout(50); - const int numTasks = 20; - for (int i = 0; i < numTasks; ++i) { - threadPool.start(&task); - QTest::qSleep(50); // exactly the same as the expiry timeout - } - QCOMPARE(int(task.runCount), numTasks); - QVERIFY(threadPool.waitForDone(2000)); -} - -#ifndef QT_NO_EXCEPTIONS -class ExceptionTask : public QRunnable -{ -public: - void run() - { - throw new int; - } -}; -#endif - -void tst_QThreadPool::exceptions() -{ -#ifndef QT_NO_EXCEPTIONS - ExceptionTask task; - { - QThreadPool threadPool; -// Uncomment this for a nice crash. -// threadPool.start(&task); - } -#else - QSKIP("No exception support", SkipAll); -#endif -} - -void tst_QThreadPool::maxThreadCount() -{ - DEPENDS_ON("setMaxThreadCount()"); -} - -void tst_QThreadPool::setMaxThreadCount_data() -{ - QTest::addColumn("limit"); - - QTest::newRow("") << 1; - QTest::newRow("") << -1; - QTest::newRow("") << 2; - QTest::newRow("") << -2; - QTest::newRow("") << 4; - QTest::newRow("") << -4; - QTest::newRow("") << 0; - QTest::newRow("") << 12345; - QTest::newRow("") << -6789; - QTest::newRow("") << 42; - QTest::newRow("") << -666; -} - -void tst_QThreadPool::setMaxThreadCount() -{ - QFETCH(int, limit); - QThreadPool *threadPool = QThreadPool::globalInstance(); - int savedLimit = threadPool->maxThreadCount(); - - // maxThreadCount() should always return the previous argument to - // setMaxThreadCount(), regardless of input - threadPool->setMaxThreadCount(limit); - QCOMPARE(threadPool->maxThreadCount(), limit); - - // the value returned from maxThreadCount() should always be valid input for setMaxThreadCount() - threadPool->setMaxThreadCount(savedLimit); - QCOMPARE(threadPool->maxThreadCount(), savedLimit); - - // setting the limit on children should have no effect on the parent - { - QThreadPool threadPool2(threadPool); - savedLimit = threadPool2.maxThreadCount(); - - // maxThreadCount() should always return the previous argument to - // setMaxThreadCount(), regardless of input - threadPool2.setMaxThreadCount(limit); - QCOMPARE(threadPool2.maxThreadCount(), limit); - - // the value returned from maxThreadCount() should always be valid input for setMaxThreadCount() - threadPool2.setMaxThreadCount(savedLimit); - QCOMPARE(threadPool2.maxThreadCount(), savedLimit); - } -} - -void tst_QThreadPool::setMaxThreadCountStartsAndStopsThreads() -{ - class WaitingTask : public QRunnable - { - public: - QSemaphore waitForStarted, waitToFinish; - - WaitingTask() { setAutoDelete(false); } - - void run() - { - waitForStarted.release(); - waitToFinish.acquire(); - } - }; - - QThreadPool threadPool; - threadPool.setMaxThreadCount(1); - - WaitingTask *task = new WaitingTask; - threadPool.start(task); - QVERIFY(task->waitForStarted.tryAcquire(1, 1000)); - - // thread limit is 1, cannot start more tasks - threadPool.start(task); - QVERIFY(!task->waitForStarted.tryAcquire(1, 1000)); - - // increasing the limit by 1 should start the task immediately - threadPool.setMaxThreadCount(2); - QVERIFY(task->waitForStarted.tryAcquire(1, 1000)); - - // ... but we still cannot start more tasks - threadPool.start(task); - QVERIFY(!task->waitForStarted.tryAcquire(1, 1000)); - - // increasing the limit should be able to start more than one at a time - threadPool.start(task); - threadPool.setMaxThreadCount(4); - QVERIFY(task->waitForStarted.tryAcquire(2, 1000)); - - // ... but we still cannot start more tasks - threadPool.start(task); - threadPool.start(task); - QVERIFY(!task->waitForStarted.tryAcquire(2, 1000)); - - // decreasing the thread limit should cause the active thread count to go down - threadPool.setMaxThreadCount(2); - QCOMPARE(threadPool.activeThreadCount(), 4); - task->waitToFinish.release(2); - QTest::qWait(1000); - QCOMPARE(threadPool.activeThreadCount(), 2); - - // ... and we still cannot start more tasks - threadPool.start(task); - threadPool.start(task); - QVERIFY(!task->waitForStarted.tryAcquire(2, 1000)); - - // start all remaining tasks - threadPool.start(task); - threadPool.start(task); - threadPool.start(task); - threadPool.start(task); - threadPool.setMaxThreadCount(8); - QVERIFY(task->waitForStarted.tryAcquire(6, 1000)); - - task->waitToFinish.release(10); -// delete task; -} - - -void tst_QThreadPool::activeThreadCount() -{ - DEPENDS_ON("tryReserveThread()"); - DEPENDS_ON("reserveThread()"); - DEPENDS_ON("releaseThread()"); -} - -void tst_QThreadPool::reserveThread_data() -{ - setMaxThreadCount_data(); -} - -void tst_QThreadPool::reserveThread() -{ - QFETCH(int, limit); - QThreadPool *threadpool = QThreadPool::globalInstance(); - int savedLimit = threadpool->maxThreadCount(); - threadpool->setMaxThreadCount(limit); - - // reserve up to the limit - for (int i = 0; i < limit; ++i) - threadpool->reserveThread(); - - // reserveThread() should always reserve a thread, regardless of - // how many have been previously reserved - threadpool->reserveThread(); - QCOMPARE(threadpool->activeThreadCount(), (limit > 0 ? limit : 0) + 1); - threadpool->reserveThread(); - QCOMPARE(threadpool->activeThreadCount(), (limit > 0 ? limit : 0) + 2); - - // cleanup - threadpool->releaseThread(); - threadpool->releaseThread(); - for (int i = 0; i < limit; ++i) - threadpool->releaseThread(); - - // reserving threads in children should not effect the parent - { - QThreadPool threadpool2(threadpool); - threadpool2.setMaxThreadCount(limit); - - // reserve up to the limit - for (int i = 0; i < limit; ++i) - threadpool2.reserveThread(); - - // reserveThread() should always reserve a thread, regardless - // of how many have been previously reserved - threadpool2.reserveThread(); - QCOMPARE(threadpool2.activeThreadCount(), (limit > 0 ? limit : 0) + 1); - threadpool2.reserveThread(); - QCOMPARE(threadpool2.activeThreadCount(), (limit > 0 ? limit : 0) + 2); - - threadpool->reserveThread(); - QCOMPARE(threadpool->activeThreadCount(), 1); - threadpool->reserveThread(); - QCOMPARE(threadpool->activeThreadCount(), 2); - - // cleanup - threadpool2.releaseThread(); - threadpool2.releaseThread(); - threadpool->releaseThread(); - threadpool->releaseThread(); - while (threadpool2.activeThreadCount() > 0) - threadpool2.releaseThread(); - } - - // reset limit on global QThreadPool - threadpool->setMaxThreadCount(savedLimit); -} - -void tst_QThreadPool::releaseThread_data() -{ - setMaxThreadCount_data(); -} - -void tst_QThreadPool::releaseThread() -{ - QFETCH(int, limit); - QThreadPool *threadpool = QThreadPool::globalInstance(); - int savedLimit = threadpool->maxThreadCount(); - threadpool->setMaxThreadCount(limit); - - // reserve up to the limit - for (int i = 0; i < limit; ++i) - threadpool->reserveThread(); - - // release should decrease the number of reserved threads - int reserved = threadpool->activeThreadCount(); - while (reserved-- > 0) { - threadpool->releaseThread(); - QCOMPARE(threadpool->activeThreadCount(), reserved); - } - QCOMPARE(threadpool->activeThreadCount(), 0); - - // releaseThread() can release more than have been reserved - threadpool->releaseThread(); - QCOMPARE(threadpool->activeThreadCount(), -1); - threadpool->reserveThread(); - QCOMPARE(threadpool->activeThreadCount(), 0); - - // releasing threads in children should not effect the parent - { - QThreadPool threadpool2(threadpool); - threadpool2.setMaxThreadCount(limit); - - // reserve up to the limit - for (int i = 0; i < limit; ++i) - threadpool2.reserveThread(); - - // release should decrease the number of reserved threads - int reserved = threadpool2.activeThreadCount(); - while (reserved-- > 0) { - threadpool2.releaseThread(); - QCOMPARE(threadpool2.activeThreadCount(), reserved); - QCOMPARE(threadpool->activeThreadCount(), 0); - } - QCOMPARE(threadpool2.activeThreadCount(), 0); - QCOMPARE(threadpool->activeThreadCount(), 0); - - // releaseThread() can release more than have been reserved - threadpool2.releaseThread(); - QCOMPARE(threadpool2.activeThreadCount(), -1); - QCOMPARE(threadpool->activeThreadCount(), 0); - threadpool2.reserveThread(); - QCOMPARE(threadpool2.activeThreadCount(), 0); - QCOMPARE(threadpool->activeThreadCount(), 0); - } - - // reset limit on global QThreadPool - threadpool->setMaxThreadCount(savedLimit); -} - -void tst_QThreadPool::reserveAndStart() // QTBUG-21051 -{ - class WaitingTask : public QRunnable - { - public: - QAtomicInt count; - QSemaphore waitForStarted; - - WaitingTask() { setAutoDelete(false); } - - void run() - { - QTest::qSleep(3000); - count.ref(); - waitForStarted.release(); - } - }; - - // Set up - QThreadPool *threadpool = QThreadPool::globalInstance(); - int savedLimit = threadpool->maxThreadCount(); - threadpool->setMaxThreadCount(1); - QCOMPARE(threadpool->activeThreadCount(), 0); - - // reserve - threadpool->reserveThread(); - QCOMPARE(threadpool->activeThreadCount(), 1); - - // start a task, to get a running thread - WaitingTask *task = new WaitingTask; - threadpool->start(task); - QCOMPARE(threadpool->activeThreadCount(), 2); - task->waitForStarted.acquire(); - QTRY_COMPARE(int(task->count), 1); - QTRY_COMPARE(threadpool->activeThreadCount(), 1); - - // now the thread is waiting, but tryStart() will fail since activeThreadCount() >= maxThreadCount() - QVERIFY(!threadpool->tryStart(task)); - QTRY_COMPARE(threadpool->activeThreadCount(), 1); - - // start() will therefore do a failing tryStart(), followed by enqueueTask() - // which will actually wake up the waiting thread. - threadpool->start(task); - QTRY_COMPARE(threadpool->activeThreadCount(), 2); - task->waitForStarted.acquire(); - QTRY_COMPARE(int(task->count), 2); - QTRY_COMPARE(threadpool->activeThreadCount(), 1); - - threadpool->releaseThread(); - QTRY_COMPARE(threadpool->activeThreadCount(), 0); - - delete task; - - threadpool->setMaxThreadCount(savedLimit); -} - -QAtomicInt count; -class CountingRunnable : public QRunnable -{ - public: void run() - { - count.ref(); - } -}; - -void tst_QThreadPool::start() -{ - const int runs = 1000; - count = 0; - { - QThreadPool threadPool; - for (int i = 0; i< runs; ++i) { - threadPool.start(new CountingRunnable()); - } - } - QCOMPARE(int(count), runs); -} - -void tst_QThreadPool::tryStart() -{ - class WaitingTask : public QRunnable - { - public: - QSemaphore semaphore; - - WaitingTask() { setAutoDelete(false); } - - void run() - { - semaphore.acquire(); - count.ref(); - } - }; - - count = 0; - - WaitingTask task; - QThreadPool threadPool; - for (int i = 0; i < threadPool.maxThreadCount(); ++i) { - threadPool.start(&task); - } - QVERIFY(!threadPool.tryStart(&task)); - task.semaphore.release(threadPool.maxThreadCount()); - threadPool.waitForDone(); - QCOMPARE(int(count), threadPool.maxThreadCount()); -} - -QMutex mutex; -QAtomicInt activeThreads(0); -QAtomicInt peakActiveThreads(0); -void tst_QThreadPool::tryStartPeakThreadCount() -{ - class CounterTask : public QRunnable - { - public: - CounterTask() { setAutoDelete(false); } - - void run() - { - { - QMutexLocker lock(&mutex); - activeThreads.ref(); - peakActiveThreads = qMax(peakActiveThreads, activeThreads); - } - - QTest::qWait(100); - { - QMutexLocker lock(&mutex); - activeThreads.deref(); - } - } - }; - - CounterTask task; - QThreadPool threadPool; - - for (int i = 0; i < 20; ++i) { - if (threadPool.tryStart(&task) == false) - QTest::qWait(10); - } - QCOMPARE(peakActiveThreads.load(), QThread::idealThreadCount()); - - for (int i = 0; i < 20; ++i) { - if (threadPool.tryStart(&task) == false) - QTest::qWait(10); - } - QCOMPARE(peakActiveThreads.load(), QThread::idealThreadCount()); -} - -void tst_QThreadPool::tryStartCount() -{ - class SleeperTask : public QRunnable - { - public: - SleeperTask() { setAutoDelete(false); } - - void run() - { - QTest::qWait(50); - } - }; - - SleeperTask task; - QThreadPool threadPool; - const int runs = 5; - - for (int i = 0; i < runs; ++i) { -// qDebug() << "iteration" << i; - int count = 0; - while (threadPool.tryStart(&task)) - ++count; - QCOMPARE(count, QThread::idealThreadCount()); - - QTest::qWait(100); - } -} - -void tst_QThreadPool::waitForDone() -{ - QElapsedTimer total, pass; - total.start(); - - QThreadPool threadPool; - while (total.elapsed() < 10000) { - int runs; - runs = count = 0; - pass.restart(); - while (pass.elapsed() < 100) { - threadPool.start(new CountingRunnable()); - ++runs; - } - threadPool.waitForDone(); - QCOMPARE(int(count), runs); - - runs = count = 0; - pass.restart(); - while (pass.elapsed() < 100) { - threadPool.start(new CountingRunnable()); - threadPool.start(new CountingRunnable()); - runs += 2; - } - threadPool.waitForDone(); - QCOMPARE(int(count), runs); - } -} - -void tst_QThreadPool::waitForDoneTimeout() -{ - class BlockedTask : public QRunnable - { - public: - QMutex mutex; - BlockedTask() { setAutoDelete(false); } - - void run() - { - mutex.lock(); - mutex.unlock(); - QTest::qSleep(50); - } - }; - - QThreadPool threadPool; - - BlockedTask *task = new BlockedTask; - task->mutex.lock(); - threadPool.start(task); - QVERIFY(!threadPool.waitForDone(100)); - task->mutex.unlock(); - QVERIFY(threadPool.waitForDone(400)); -} - -void tst_QThreadPool::destroyingWaitsForTasksToFinish() -{ - QElapsedTimer total, pass; - total.start(); - - while (total.elapsed() < 10000) { - int runs; - runs = count = 0; - { - QThreadPool threadPool; - pass.restart(); - while (pass.elapsed() < 100) { - threadPool.start(new CountingRunnable()); - ++runs; - } - } - QCOMPARE(int(count), runs); - - runs = count = 0; - { - QThreadPool threadPool; - pass.restart(); - while (pass.elapsed() < 100) { - threadPool.start(new CountingRunnable()); - threadPool.start(new CountingRunnable()); - runs += 2; - } - } - QCOMPARE(int(count), runs); - } -} - -void tst_QThreadPool::stressTest() -{ - class Task : public QRunnable - { - QSemaphore semaphore; - public: - Task() { setAutoDelete(false); } - - void start() - { - QThreadPool::globalInstance()->start(this); - } - - void wait() - { - semaphore.acquire(); - } - - void run() - { - semaphore.release(); - } - }; - - QElapsedTimer total; - total.start(); - while (total.elapsed() < 30000) { - Task t; - t.start(); - t.wait(); - } -} - -QTEST_MAIN(tst_QThreadPool); -#include "moc_tst_qthreadpool.cpp"