diff options
Diffstat (limited to 'tests/auto/corelib/thread/qthreadpool')
-rw-r--r-- | tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp index 094c6ed0a5..1092216fb7 100644 --- a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp +++ b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp @@ -95,6 +95,7 @@ private slots: void stackSize(); void stressTest(); void takeAllAndIncreaseMaxThreadCount(); + void waitForDoneAfterTake(); private: QMutex m_functionTestMutex; @@ -1267,5 +1268,72 @@ void tst_QThreadPool::takeAllAndIncreaseMaxThreadCount() { delete task3; } +void tst_QThreadPool::waitForDoneAfterTake() +{ + class Task : public QRunnable + { + public: + Task(QSemaphore *mainBarrier, QSemaphore *threadBarrier) + : m_mainBarrier(mainBarrier) + , m_threadBarrier(threadBarrier) + {} + + void run() + { + m_mainBarrier->release(); + m_threadBarrier->acquire(); + } + + private: + QSemaphore *m_mainBarrier = nullptr; + QSemaphore *m_threadBarrier = nullptr; + }; + + int threadCount = 4; + + // Blocks the main thread from releasing the threadBarrier before all run() functions have started + QSemaphore mainBarrier; + // Blocks the tasks from completing their run function + QSemaphore threadBarrier; + + QThreadPool manager; + manager.setMaxThreadCount(threadCount); + + // Fill all the threads with runnables that wait for the threadBarrier + for (int i = 0; i < threadCount; i++) { + auto *task = new Task(&mainBarrier, &threadBarrier); + manager.start(task); + } + + QVERIFY(manager.activeThreadCount() == manager.maxThreadCount()); + + // Add runnables that are immediately removed from the pool queue. + // This sets the queue elements to nullptr in QThreadPool and we want to test that + // the threads keep going through the queue after encountering a nullptr. + for (int i = 0; i < threadCount; i++) { + QRunnable *runnable = createTask(emptyFunct); + manager.start(runnable); + QVERIFY(manager.tryTake(runnable)); + } + + // Add another runnable that will not be removed + manager.start(createTask(emptyFunct)); + + // Wait for the first runnables to start + mainBarrier.acquire(threadCount); + + QVERIFY(mainBarrier.available() == 0); + QVERIFY(threadBarrier.available() == 0); + + // Release runnables that are waiting and expect all runnables to complete + threadBarrier.release(threadCount); + + // Using qFatal instead of QVERIFY to force exit if threads are still running after timeout. + // Otherwise, QCoreApplication will still wait for the stale threads and never exit the test. + if (!manager.waitForDone(5 * 60 * 1000)) + qFatal("waitForDone returned false. Aborting to stop background threads."); + +} + QTEST_MAIN(tst_QThreadPool); #include "tst_qthreadpool.moc" |