tests/auto/qthreadpool/tst_qthreadpool.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 #include <QtTest/QtTest>
       
    42 #include <qdatetime.h>
       
    43 #include <qthreadpool.h>
       
    44 #include <qstring.h>
       
    45 #include <qmutex.h>
       
    46 
       
    47 typedef void (*FunctionPointer)();
       
    48 
       
    49 class FunctionPointerTask : public QRunnable
       
    50 {
       
    51 public:
       
    52     FunctionPointerTask(FunctionPointer function)
       
    53     :function(function) {}
       
    54     void run() { function(); }
       
    55 private:
       
    56     FunctionPointer function;
       
    57 };
       
    58 
       
    59 QRunnable *createTask(FunctionPointer pointer)
       
    60 {
       
    61     return new FunctionPointerTask(pointer);
       
    62 }
       
    63 
       
    64 class tst_QThreadPool : public QObject
       
    65 {
       
    66     Q_OBJECT
       
    67 private slots:
       
    68     void runFunction();
       
    69     void createThreadRunFunction();
       
    70     void runMultiple();
       
    71     void waitcomplete();
       
    72     void runTask();
       
    73     void singleton();
       
    74     void destruction();
       
    75     void threadRecycling();
       
    76     void expiryTimeout();
       
    77     void exceptions();
       
    78     void maxThreadCount();
       
    79     void setMaxThreadCount_data();
       
    80     void setMaxThreadCount();
       
    81     void setMaxThreadCountStartsAndStopsThreads();
       
    82     void activeThreadCount();
       
    83     void reserveThread_data();
       
    84     void reserveThread();
       
    85     void releaseThread_data();
       
    86     void releaseThread();
       
    87     void start();
       
    88     void tryStart();
       
    89     void tryStartPeakThreadCount();
       
    90     void tryStartCount();
       
    91     void waitForDone();
       
    92     void destroyingWaitsForTasksToFinish();
       
    93     void stressTest();
       
    94 };
       
    95 
       
    96 int testFunctionCount;
       
    97 
       
    98 void sleepTestFunction()
       
    99 {
       
   100     QTest::qSleep(1000);
       
   101     ++testFunctionCount;
       
   102 }
       
   103 
       
   104 void emptyFunct()
       
   105 {
       
   106 
       
   107 }
       
   108 
       
   109 void noSleepTestFunction()
       
   110 {
       
   111     ++testFunctionCount;
       
   112 }
       
   113 
       
   114 void sleepTestFunctionMutex()
       
   115 {
       
   116     static QMutex testMutex;
       
   117     QTest::qSleep(1000);
       
   118     testMutex.lock();
       
   119     ++testFunctionCount;
       
   120     testMutex.unlock();
       
   121 }
       
   122 
       
   123 void noSleepTestFunctionMutex()
       
   124 {
       
   125     static QMutex testMutex;
       
   126     testMutex.lock();
       
   127     ++testFunctionCount;
       
   128     testMutex.unlock();
       
   129 }
       
   130 
       
   131 void tst_QThreadPool::runFunction()
       
   132 {
       
   133     {
       
   134         QThreadPool manager;
       
   135         testFunctionCount = 0;
       
   136         manager.start(createTask(noSleepTestFunction));
       
   137     }
       
   138     QCOMPARE(testFunctionCount, 1);
       
   139 }
       
   140 
       
   141 void tst_QThreadPool::createThreadRunFunction()
       
   142 {
       
   143     {
       
   144         QThreadPool manager;
       
   145         testFunctionCount = 0;
       
   146         manager.start(createTask(noSleepTestFunction));
       
   147     }
       
   148 
       
   149     QCOMPARE(testFunctionCount, 1);
       
   150 }
       
   151 
       
   152 void tst_QThreadPool::runMultiple()
       
   153 {
       
   154     const int runs = 10;
       
   155 
       
   156     {
       
   157         QThreadPool manager;
       
   158         testFunctionCount = 0;
       
   159         for (int i = 0; i < runs; ++i) {
       
   160             manager.start(createTask(sleepTestFunctionMutex));
       
   161         }
       
   162     }
       
   163     QCOMPARE(testFunctionCount, runs);
       
   164 
       
   165     {
       
   166         QThreadPool manager;
       
   167         testFunctionCount = 0;
       
   168         for (int i = 0; i < runs; ++i) {
       
   169             manager.start(createTask(noSleepTestFunctionMutex));
       
   170         }
       
   171     }
       
   172     QCOMPARE(testFunctionCount, runs);
       
   173 
       
   174     {
       
   175         QThreadPool manager;
       
   176         for (int i = 0; i < 500; ++i)
       
   177             manager.start(createTask(emptyFunct));
       
   178     }
       
   179 }
       
   180 
       
   181 void tst_QThreadPool::waitcomplete()
       
   182 {
       
   183     testFunctionCount = 0;
       
   184     const int runs = 500;
       
   185     for (int i = 0; i < 500; ++i) {
       
   186         QThreadPool pool;
       
   187         pool.start(createTask(noSleepTestFunction));
       
   188     }
       
   189     QCOMPARE(testFunctionCount, runs);
       
   190 }
       
   191 
       
   192 volatile bool ran;
       
   193 class TestTask : public QRunnable
       
   194 {
       
   195 public:
       
   196     void run()
       
   197     {
       
   198         ran = true;
       
   199     }
       
   200 };
       
   201 
       
   202 void tst_QThreadPool::runTask()
       
   203 {
       
   204     QThreadPool manager;
       
   205     ran = false;
       
   206     manager.start(new TestTask());
       
   207     // Hang if task is not runned.
       
   208     while (ran == false)
       
   209         QTest::qSleep(100); // no busy loop - this doesn't work with FIFO schedulers
       
   210 }
       
   211 
       
   212 /*
       
   213     Test running via QThreadPool::globalInstance()
       
   214 */
       
   215 void tst_QThreadPool::singleton()
       
   216 {
       
   217     ran = false;
       
   218     QThreadPool::globalInstance()->start(new TestTask());
       
   219     while (ran == false)
       
   220         QTest::qSleep(100); // no busy loop - this doesn't work with FIFO schedulers
       
   221 }
       
   222 
       
   223 int *value = 0;
       
   224 class IntAccessor : public QRunnable
       
   225 {
       
   226 public:
       
   227     void run()
       
   228     {
       
   229         for (int i = 0; i < 100; ++i) {
       
   230             ++(*value);
       
   231             QTest::qSleep(1);
       
   232         }
       
   233     }
       
   234 };
       
   235 
       
   236 /*
       
   237     Test that the ThreadManager destructor waits until
       
   238     all threads have completed.
       
   239 */
       
   240 void tst_QThreadPool::destruction()
       
   241 {
       
   242     value = new int;
       
   243     QThreadPool *threadManager = new QThreadPool();
       
   244     threadManager->start(new IntAccessor());
       
   245     threadManager->start(new IntAccessor());
       
   246     delete threadManager;
       
   247     delete value;
       
   248     value = 0;
       
   249 }
       
   250 
       
   251 QSemaphore threadRecyclingSemaphore;
       
   252 QThread *recycledThread = 0;
       
   253 
       
   254 class ThreadRecorderTask : public QRunnable
       
   255 {
       
   256 public:
       
   257     void run()
       
   258     {
       
   259         recycledThread = QThread::currentThread();
       
   260         threadRecyclingSemaphore.release();
       
   261     }
       
   262 };
       
   263 
       
   264 /*
       
   265     Test that the thread pool really reuses threads.
       
   266 */
       
   267 void tst_QThreadPool::threadRecycling()
       
   268 {
       
   269     QThreadPool threadPool;
       
   270 
       
   271     threadPool.start(new ThreadRecorderTask());
       
   272     threadRecyclingSemaphore.acquire();
       
   273     QThread *thread1 = recycledThread;
       
   274 
       
   275     QTest::qSleep(100);
       
   276 
       
   277     threadPool.start(new ThreadRecorderTask());
       
   278     threadRecyclingSemaphore.acquire();
       
   279     QThread *thread2 = recycledThread;
       
   280     QCOMPARE(thread1, thread2);
       
   281 
       
   282     QTest::qSleep(100);
       
   283 
       
   284     threadPool.start(new ThreadRecorderTask());
       
   285     threadRecyclingSemaphore.acquire();
       
   286     QThread *thread3 = recycledThread;
       
   287     QCOMPARE(thread2, thread3);
       
   288 }
       
   289 
       
   290 class ExpiryTimeoutTask : public QRunnable
       
   291 {
       
   292 public:
       
   293     QThread *thread;
       
   294     int runCount;
       
   295     QSemaphore semaphore;
       
   296 
       
   297     ExpiryTimeoutTask()
       
   298         : thread(0), runCount(0)
       
   299     {
       
   300         setAutoDelete(false);
       
   301     }
       
   302 
       
   303     void run()
       
   304     {
       
   305         thread = QThread::currentThread();
       
   306         ++runCount;
       
   307         semaphore.release();
       
   308     }
       
   309 };
       
   310 
       
   311 void tst_QThreadPool::expiryTimeout()
       
   312 {
       
   313     ExpiryTimeoutTask task;
       
   314 
       
   315     QThreadPool threadPool;
       
   316     threadPool.setMaxThreadCount(1);
       
   317 
       
   318     int expiryTimeout = threadPool.expiryTimeout();
       
   319     threadPool.setExpiryTimeout(1000);
       
   320     QCOMPARE(threadPool.expiryTimeout(), 1000);
       
   321 
       
   322     // run the task
       
   323     threadPool.start(&task);
       
   324     QVERIFY(task.semaphore.tryAcquire(1, 10000));
       
   325     QCOMPARE(task.runCount, 1);
       
   326     QVERIFY(!task.thread->wait(100));
       
   327     // thread should expire
       
   328     QThread *firstThread = task.thread;
       
   329     QVERIFY(task.thread->wait(10000));
       
   330 
       
   331     // run task again, thread should be restarted
       
   332     threadPool.start(&task);
       
   333     QVERIFY(task.semaphore.tryAcquire(1, 10000));
       
   334     QCOMPARE(task.runCount, 2);
       
   335     QVERIFY(!task.thread->wait(100));
       
   336     // thread should expire again
       
   337     QVERIFY(task.thread->wait(10000));
       
   338 
       
   339     // thread pool should have reused the expired thread (instead of
       
   340     // starting a new one)
       
   341     QCOMPARE(firstThread, task.thread);
       
   342 
       
   343     threadPool.setExpiryTimeout(expiryTimeout);
       
   344     QCOMPARE(threadPool.expiryTimeout(), expiryTimeout);
       
   345 }
       
   346 
       
   347 #ifndef QT_NO_EXCEPTIONS
       
   348 class ExceptionTask : public QRunnable
       
   349 {
       
   350 public:
       
   351     void run()
       
   352     {
       
   353         throw new int;
       
   354     }
       
   355 };
       
   356 #endif
       
   357 
       
   358 void tst_QThreadPool::exceptions()
       
   359 {
       
   360 #ifndef QT_NO_EXCEPTIONS
       
   361     ExceptionTask task;
       
   362     {
       
   363         QThreadPool threadPool;
       
   364 //  Uncomment this for a nice crash.
       
   365 //        threadPool.start(&task);
       
   366     }
       
   367 #else
       
   368     QSKIP("No exception support", SkipAll);
       
   369 #endif
       
   370 }
       
   371 
       
   372 void tst_QThreadPool::maxThreadCount()
       
   373 {
       
   374     DEPENDS_ON("setMaxThreadCount()");
       
   375 }
       
   376 
       
   377 void tst_QThreadPool::setMaxThreadCount_data()
       
   378 {
       
   379     QTest::addColumn<int>("limit");
       
   380 
       
   381     QTest::newRow("") << 1;
       
   382     QTest::newRow("") << -1;
       
   383     QTest::newRow("") << 2;
       
   384     QTest::newRow("") << -2;
       
   385     QTest::newRow("") << 4;
       
   386     QTest::newRow("") << -4;
       
   387     QTest::newRow("") << 0;
       
   388     QTest::newRow("") << 12345;
       
   389     QTest::newRow("") << -6789;
       
   390     QTest::newRow("") << 42;
       
   391     QTest::newRow("") << -666;
       
   392 }
       
   393 
       
   394 void tst_QThreadPool::setMaxThreadCount()
       
   395 {
       
   396     QFETCH(int, limit);
       
   397     QThreadPool *threadPool = QThreadPool::globalInstance();
       
   398     int savedLimit = threadPool->maxThreadCount();
       
   399 
       
   400     // maxThreadCount() should always return the previous argument to
       
   401     // setMaxThreadCount(), regardless of input
       
   402     threadPool->setMaxThreadCount(limit);
       
   403     QCOMPARE(threadPool->maxThreadCount(), limit);
       
   404 
       
   405     // the value returned from maxThreadCount() should always be valid input for setMaxThreadCount()
       
   406     threadPool->setMaxThreadCount(savedLimit);
       
   407     QCOMPARE(threadPool->maxThreadCount(), savedLimit);
       
   408 
       
   409     // setting the limit on children should have no effect on the parent
       
   410     {
       
   411         QThreadPool threadPool2(threadPool);
       
   412         savedLimit = threadPool2.maxThreadCount();
       
   413 
       
   414         // maxThreadCount() should always return the previous argument to
       
   415         // setMaxThreadCount(), regardless of input
       
   416         threadPool2.setMaxThreadCount(limit);
       
   417         QCOMPARE(threadPool2.maxThreadCount(), limit);
       
   418 
       
   419         // the value returned from maxThreadCount() should always be valid input for setMaxThreadCount()
       
   420         threadPool2.setMaxThreadCount(savedLimit);
       
   421         QCOMPARE(threadPool2.maxThreadCount(), savedLimit);
       
   422     }
       
   423 }
       
   424 
       
   425 void tst_QThreadPool::setMaxThreadCountStartsAndStopsThreads()
       
   426 {
       
   427     class WaitingTask : public QRunnable
       
   428     {
       
   429     public:
       
   430         QSemaphore waitForStarted, waitToFinish;
       
   431 
       
   432         WaitingTask() { setAutoDelete(false); }
       
   433 
       
   434         void run()
       
   435         {
       
   436             waitForStarted.release();
       
   437             waitToFinish.acquire();
       
   438         }
       
   439     };
       
   440 
       
   441     QThreadPool threadPool;
       
   442     threadPool.setMaxThreadCount(1);
       
   443 
       
   444     WaitingTask *task = new WaitingTask;
       
   445     threadPool.start(task);
       
   446     QVERIFY(task->waitForStarted.tryAcquire(1, 1000));
       
   447 
       
   448     // thread limit is 1, cannot start more tasks
       
   449     threadPool.start(task);
       
   450     QVERIFY(!task->waitForStarted.tryAcquire(1, 1000));
       
   451 
       
   452     // increasing the limit by 1 should start the task immediately
       
   453     threadPool.setMaxThreadCount(2);
       
   454     QVERIFY(task->waitForStarted.tryAcquire(1, 1000));
       
   455 
       
   456     // ... but we still cannot start more tasks
       
   457     threadPool.start(task);
       
   458     QVERIFY(!task->waitForStarted.tryAcquire(1, 1000));
       
   459 
       
   460     // increasing the limit should be able to start more than one at a time
       
   461     threadPool.start(task);
       
   462     threadPool.setMaxThreadCount(4);
       
   463     QVERIFY(task->waitForStarted.tryAcquire(2, 1000));
       
   464 
       
   465     // ... but we still cannot start more tasks
       
   466     threadPool.start(task);
       
   467     threadPool.start(task);
       
   468     QVERIFY(!task->waitForStarted.tryAcquire(2, 1000));
       
   469 
       
   470     // decreasing the thread limit should cause the active thread count to go down
       
   471     threadPool.setMaxThreadCount(2);
       
   472     QCOMPARE(threadPool.activeThreadCount(), 4);
       
   473     task->waitToFinish.release(2);
       
   474     QTest::qWait(1000);
       
   475     QCOMPARE(threadPool.activeThreadCount(), 2);
       
   476 
       
   477     // ... and we still cannot start more tasks
       
   478     threadPool.start(task);
       
   479     threadPool.start(task);
       
   480     QVERIFY(!task->waitForStarted.tryAcquire(2, 1000));
       
   481 
       
   482     // start all remaining tasks
       
   483     threadPool.start(task);
       
   484     threadPool.start(task);
       
   485     threadPool.start(task);
       
   486     threadPool.start(task);
       
   487     threadPool.setMaxThreadCount(8);
       
   488     QVERIFY(task->waitForStarted.tryAcquire(6, 1000));
       
   489 
       
   490     task->waitToFinish.release(10);
       
   491 //    delete task;
       
   492 }
       
   493 
       
   494 
       
   495 void tst_QThreadPool::activeThreadCount()
       
   496 {
       
   497     DEPENDS_ON("tryReserveThread()");
       
   498     DEPENDS_ON("reserveThread()");
       
   499     DEPENDS_ON("releaseThread()");
       
   500 }
       
   501 
       
   502 void tst_QThreadPool::reserveThread_data()
       
   503 {
       
   504     setMaxThreadCount_data();
       
   505 }
       
   506 
       
   507 void tst_QThreadPool::reserveThread()
       
   508 {
       
   509     QFETCH(int, limit);
       
   510     QThreadPool *threadpool = QThreadPool::globalInstance();
       
   511     int savedLimit = threadpool->maxThreadCount();
       
   512     threadpool->setMaxThreadCount(limit);
       
   513 
       
   514     // reserve up to the limit
       
   515     for (int i = 0; i < limit; ++i)
       
   516         threadpool->reserveThread();
       
   517 
       
   518     // reserveThread() should always reserve a thread, regardless of
       
   519     // how many have been previously reserved
       
   520     threadpool->reserveThread();
       
   521     QCOMPARE(threadpool->activeThreadCount(), (limit > 0 ? limit : 0) + 1);
       
   522     threadpool->reserveThread();
       
   523     QCOMPARE(threadpool->activeThreadCount(), (limit > 0 ? limit : 0) + 2);
       
   524 
       
   525     // cleanup
       
   526     threadpool->releaseThread();
       
   527     threadpool->releaseThread();
       
   528     for (int i = 0; i < limit; ++i)
       
   529         threadpool->releaseThread();
       
   530 
       
   531     // reserving threads in children should not effect the parent
       
   532     {
       
   533         QThreadPool threadpool2(threadpool);
       
   534         threadpool2.setMaxThreadCount(limit);
       
   535 
       
   536         // reserve up to the limit
       
   537         for (int i = 0; i < limit; ++i)
       
   538             threadpool2.reserveThread();
       
   539 
       
   540         // reserveThread() should always reserve a thread, regardless
       
   541         // of how many have been previously reserved
       
   542         threadpool2.reserveThread();
       
   543         QCOMPARE(threadpool2.activeThreadCount(), (limit > 0 ? limit : 0) + 1);
       
   544         threadpool2.reserveThread();
       
   545         QCOMPARE(threadpool2.activeThreadCount(), (limit > 0 ? limit : 0) + 2);
       
   546 
       
   547         threadpool->reserveThread();
       
   548         QCOMPARE(threadpool->activeThreadCount(), 1);
       
   549         threadpool->reserveThread();
       
   550         QCOMPARE(threadpool->activeThreadCount(), 2);
       
   551 
       
   552         // cleanup
       
   553         threadpool2.releaseThread();
       
   554         threadpool2.releaseThread();
       
   555         threadpool->releaseThread();
       
   556         threadpool->releaseThread();
       
   557         while (threadpool2.activeThreadCount() > 0)
       
   558             threadpool2.releaseThread();
       
   559     }
       
   560 
       
   561     // reset limit on global QThreadPool
       
   562     threadpool->setMaxThreadCount(savedLimit);
       
   563 }
       
   564 
       
   565 void tst_QThreadPool::releaseThread_data()
       
   566 {
       
   567     setMaxThreadCount_data();
       
   568 }
       
   569 
       
   570 void tst_QThreadPool::releaseThread()
       
   571 {
       
   572     QFETCH(int, limit);
       
   573     QThreadPool *threadpool = QThreadPool::globalInstance();
       
   574     int savedLimit = threadpool->maxThreadCount();
       
   575     threadpool->setMaxThreadCount(limit);
       
   576 
       
   577     // reserve up to the limit
       
   578     for (int i = 0; i < limit; ++i)
       
   579         threadpool->reserveThread();
       
   580 
       
   581     // release should decrease the number of reserved threads
       
   582     int reserved = threadpool->activeThreadCount();
       
   583     while (reserved-- > 0) {
       
   584         threadpool->releaseThread();
       
   585         QCOMPARE(threadpool->activeThreadCount(), reserved);
       
   586     }
       
   587     QCOMPARE(threadpool->activeThreadCount(), 0);
       
   588 
       
   589     // releaseThread() can release more than have been reserved
       
   590     threadpool->releaseThread();
       
   591     QCOMPARE(threadpool->activeThreadCount(), -1);
       
   592     threadpool->reserveThread();
       
   593     QCOMPARE(threadpool->activeThreadCount(), 0);
       
   594 
       
   595     // releasing threads in children should not effect the parent
       
   596     {
       
   597         QThreadPool threadpool2(threadpool);
       
   598         threadpool2.setMaxThreadCount(limit);
       
   599 
       
   600         // reserve up to the limit
       
   601         for (int i = 0; i < limit; ++i)
       
   602             threadpool2.reserveThread();
       
   603 
       
   604         // release should decrease the number of reserved threads
       
   605         int reserved = threadpool2.activeThreadCount();
       
   606         while (reserved-- > 0) {
       
   607             threadpool2.releaseThread();
       
   608             QCOMPARE(threadpool2.activeThreadCount(), reserved);
       
   609             QCOMPARE(threadpool->activeThreadCount(), 0);
       
   610         }
       
   611         QCOMPARE(threadpool2.activeThreadCount(), 0);
       
   612         QCOMPARE(threadpool->activeThreadCount(), 0);
       
   613 
       
   614         // releaseThread() can release more than have been reserved
       
   615         threadpool2.releaseThread();
       
   616         QCOMPARE(threadpool2.activeThreadCount(), -1);
       
   617         QCOMPARE(threadpool->activeThreadCount(), 0);
       
   618         threadpool2.reserveThread();
       
   619         QCOMPARE(threadpool2.activeThreadCount(), 0);
       
   620         QCOMPARE(threadpool->activeThreadCount(), 0);
       
   621     }
       
   622 
       
   623     // reset limit on global QThreadPool
       
   624     threadpool->setMaxThreadCount(savedLimit);
       
   625 }
       
   626 
       
   627 QAtomicInt count;
       
   628 class CountingRunnable : public QRunnable
       
   629 {
       
   630     public: void run()
       
   631     {
       
   632         count.ref();
       
   633     }
       
   634 };
       
   635 
       
   636 void tst_QThreadPool::start()
       
   637 {
       
   638     const int runs = 1000;
       
   639     count = 0;
       
   640     {
       
   641         QThreadPool threadPool;
       
   642         for (int i = 0; i< runs; ++i) {
       
   643             threadPool.start(new CountingRunnable());
       
   644         }
       
   645     }
       
   646     QCOMPARE(int(count), runs);
       
   647 }
       
   648 
       
   649 void tst_QThreadPool::tryStart()
       
   650 {
       
   651     class WaitingTask : public QRunnable
       
   652     {
       
   653     public:
       
   654         QSemaphore semaphore;
       
   655 
       
   656         WaitingTask() { setAutoDelete(false); }
       
   657 
       
   658         void run()
       
   659         {
       
   660             semaphore.acquire();
       
   661             count.ref();
       
   662         }
       
   663     };
       
   664 
       
   665     count = 0;
       
   666 
       
   667     WaitingTask task;
       
   668     QThreadPool threadPool;
       
   669     for (int i = 0; i < threadPool.maxThreadCount(); ++i) {
       
   670         threadPool.start(&task);
       
   671     }
       
   672     QVERIFY(!threadPool.tryStart(&task));
       
   673     task.semaphore.release(threadPool.maxThreadCount());
       
   674     threadPool.waitForDone();
       
   675     QCOMPARE(int(count), threadPool.maxThreadCount());
       
   676 }
       
   677 
       
   678 QMutex mutex;
       
   679 int activeThreads = 0;
       
   680 int peakActiveThreads = 0;
       
   681 void tst_QThreadPool::tryStartPeakThreadCount()
       
   682 {
       
   683     class CounterTask : public QRunnable
       
   684     {
       
   685     public:
       
   686         CounterTask() { setAutoDelete(false); }
       
   687 
       
   688         void run()
       
   689         {
       
   690             {
       
   691                 QMutexLocker lock(&mutex);
       
   692                 ++activeThreads;
       
   693                 peakActiveThreads = qMax(peakActiveThreads, activeThreads);
       
   694             }
       
   695 
       
   696             QTest::qWait(100);
       
   697             {
       
   698                 QMutexLocker lock(&mutex);
       
   699                 --activeThreads;
       
   700             }
       
   701         }
       
   702     };
       
   703 
       
   704     CounterTask task;
       
   705     QThreadPool threadPool;
       
   706 
       
   707     for (int i = 0; i < 20; ++i) {
       
   708         if (threadPool.tryStart(&task) == false)
       
   709             QTest::qWait(10);
       
   710     }
       
   711     QCOMPARE(peakActiveThreads, QThread::idealThreadCount());
       
   712 
       
   713     for (int i = 0; i < 20; ++i) {
       
   714         if (threadPool.tryStart(&task) == false)
       
   715             QTest::qWait(10);
       
   716     }
       
   717     QCOMPARE(peakActiveThreads, QThread::idealThreadCount());
       
   718 }
       
   719 
       
   720 void tst_QThreadPool::tryStartCount()
       
   721 {
       
   722     class SleeperTask : public QRunnable
       
   723     {
       
   724     public:
       
   725         SleeperTask() { setAutoDelete(false); }
       
   726 
       
   727         void run()
       
   728         {
       
   729             QTest::qWait(50);
       
   730         }
       
   731     };
       
   732 
       
   733     SleeperTask task;
       
   734     QThreadPool threadPool;
       
   735     const int runs = 5;
       
   736 
       
   737     for (int i = 0; i < runs; ++i) {
       
   738 //        qDebug() << "iteration" << i;
       
   739         int count = 0;
       
   740         while (threadPool.tryStart(&task))
       
   741             ++count;
       
   742         QCOMPARE(count, QThread::idealThreadCount());
       
   743 
       
   744         QTest::qWait(100);
       
   745     }
       
   746 }
       
   747 
       
   748 void tst_QThreadPool::waitForDone()
       
   749 {
       
   750     QTime total, pass;
       
   751     total.start();
       
   752 
       
   753     QThreadPool threadPool;
       
   754     while (total.elapsed() < 10000) {
       
   755         int runs;
       
   756         runs = count = 0;
       
   757         pass.restart();
       
   758         while (pass.elapsed() < 100) {
       
   759             threadPool.start(new CountingRunnable());
       
   760             ++runs;
       
   761         }
       
   762         threadPool.waitForDone();
       
   763         QCOMPARE(int(count), runs);
       
   764 
       
   765         runs = count = 0;
       
   766         pass.restart();
       
   767         while (pass.elapsed() < 100) {
       
   768             threadPool.start(new CountingRunnable());
       
   769             threadPool.start(new CountingRunnable());
       
   770             runs += 2;
       
   771         }
       
   772         threadPool.waitForDone();
       
   773         QCOMPARE(int(count), runs);
       
   774     }
       
   775 }
       
   776 
       
   777 void tst_QThreadPool::destroyingWaitsForTasksToFinish()
       
   778 {
       
   779     QTime total, pass;
       
   780     total.start();
       
   781 
       
   782     while (total.elapsed() < 10000) {
       
   783         int runs;
       
   784         runs = count = 0;
       
   785         {
       
   786             QThreadPool threadPool;
       
   787             pass.restart();
       
   788             while (pass.elapsed() < 100) {
       
   789                 threadPool.start(new CountingRunnable());
       
   790                 ++runs;
       
   791             }
       
   792         }
       
   793         QCOMPARE(int(count), runs);
       
   794 
       
   795         runs = count = 0;
       
   796         {
       
   797             QThreadPool threadPool;
       
   798             pass.restart();
       
   799             while (pass.elapsed() < 100) {
       
   800                 threadPool.start(new CountingRunnable());
       
   801                 threadPool.start(new CountingRunnable());
       
   802                 runs += 2;
       
   803             }
       
   804         }
       
   805         QCOMPARE(int(count), runs);
       
   806     }
       
   807 }
       
   808 
       
   809 void tst_QThreadPool::stressTest()
       
   810 {
       
   811     class Task : public QRunnable
       
   812     {
       
   813         QSemaphore semaphore;
       
   814     public:
       
   815         Task() { setAutoDelete(false); }
       
   816 
       
   817         void start()
       
   818         {
       
   819             QThreadPool::globalInstance()->start(this);
       
   820         }
       
   821 
       
   822         void wait()
       
   823         {
       
   824             semaphore.acquire();
       
   825         }
       
   826 
       
   827         void run()
       
   828         {
       
   829             semaphore.release();
       
   830         }
       
   831     };
       
   832 
       
   833     QTime total;
       
   834     total.start();
       
   835     while (total.elapsed() < 30000) {
       
   836         Task t;
       
   837         t.start();
       
   838         t.wait();
       
   839     }
       
   840 }
       
   841 
       
   842 QTEST_MAIN(tst_QThreadPool);
       
   843 #include "tst_qthreadpool.moc"