qtconcurrentthreadengine.h

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
00004 ** All rights reserved.
00005 ** Contact: Nokia Corporation (qt-info@nokia.com)
00006 **
00007 ** This file is part of the QtCore module of the Qt Toolkit.
00008 **
00009 ** $QT_BEGIN_LICENSE:LGPL$
00010 ** Commercial Usage
00011 ** Licensees holding valid Qt Commercial licenses may use this file in
00012 ** accordance with the Qt Commercial License Agreement provided with the
00013 ** Software or, alternatively, in accordance with the terms contained in
00014 ** a written agreement between you and Nokia.
00015 **
00016 ** GNU Lesser General Public License Usage
00017 ** Alternatively, this file may be used under the terms of the GNU Lesser
00018 ** General Public License version 2.1 as published by the Free Software
00019 ** Foundation and appearing in the file LICENSE.LGPL included in the
00020 ** packaging of this file.  Please review the following information to
00021 ** ensure the GNU Lesser General Public License version 2.1 requirements
00022 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
00023 **
00024 ** In addition, as a special exception, Nokia gives you certain additional
00025 ** rights.  These rights are described in the Nokia Qt LGPL Exception
00026 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this module.
00027 **
00028 ** GNU General Public License Usage
00029 ** Alternatively, this file may be used under the terms of the GNU
00030 ** General Public License version 3.0 as published by the Free Software
00031 ** Foundation and appearing in the file LICENSE.GPL included in the
00032 ** packaging of this file.  Please review the following information to
00033 ** ensure the GNU General Public License version 3.0 requirements will be
00034 ** met: http://www.gnu.org/copyleft/gpl.html.
00035 **
00036 ** If you have questions regarding the use of this file, please contact
00037 ** Nokia at qt-info@nokia.com.
00038 ** $QT_END_LICENSE$
00039 **
00040 ****************************************************************************/
00041 
00042 #ifndef QTCONCURRENT_THREADENGINE_H
00043 #define QTCONCURRENT_THREADENGINE_H
00044 
00045 #include <QtCore/qglobal.h>
00046 
00047 #ifndef QT_NO_CONCURRENT
00048 
00049 #include <QtCore/qthreadpool.h>
00050 #include <QtCore/qfuture.h>
00051 #include <QtCore/qdebug.h>
00052 #include <QtCore/qtconcurrentexception.h>
00053 #include <QtCore/qwaitcondition.h>
00054 #include <QtCore/qatomic.h>
00055 #include <QtCore/qsemaphore.h>
00056 
00057 QT_BEGIN_HEADER
00058 QT_BEGIN_NAMESPACE
00059 
00060 QT_MODULE(Core)
00061 
00062 #ifndef qdoc
00063 
00064 namespace QtConcurrent {
00065 
00066 // The ThreadEngineBarrier counts worker threads, and allows one
00067 // thread to wait for all others to finish. Tested for its use in
00068 // QtConcurrent, requires more testing for use as a general class.
00069 class ThreadEngineBarrier
00070 {
00071 private:
00072     // The thread count is maintained as an integer in the count atomic
00073     // variable. The count can be either positive or negative - a negative
00074     // count signals that a thread is waiting on the barrier.
00075 
00076     // BC note: inlined code from Qt < 4.6 will expect to find the QMutex 
00077     // and QAtomicInt here. ### Qt 5: remove.
00078     QMutex mutex;
00079     QAtomicInt count;
00080 
00081     QSemaphore semaphore;
00082 public:
00083     ThreadEngineBarrier();
00084     void acquire();
00085     int release();
00086     void wait();
00087     int currentCount();
00088     bool releaseUnlessLast();
00089 };
00090 
00091 enum ThreadFunctionResult { ThrottleThread, ThreadFinished };
00092 
00093 // The ThreadEngine controls the threads used in the computation.
00094 // Can be run in three modes: single threaded, multi-threaded blocking
00095 // and multi-threaded asynchronous.
00096 // The code for the single threaded mode is
00097 class Q_CORE_EXPORT ThreadEngineBase: public QRunnable
00098 {
00099 public:
00100     // Public API:
00101     ThreadEngineBase();
00102     virtual ~ThreadEngineBase();
00103     void startSingleThreaded();
00104     void startBlocking();
00105     void startThread();
00106     bool isCanceled();
00107     void waitForResume();
00108     bool isProgressReportingEnabled();
00109     void setProgressValue(int progress);
00110     void setProgressRange(int minimum, int maximum);
00111     void acquireBarrierSemaphore();
00112 
00113 protected: // The user overrides these:
00114     virtual void start() {}
00115     virtual void finish() {}
00116     virtual ThreadFunctionResult threadFunction() { return ThreadFinished; }
00117     virtual bool shouldStartThread() { return futureInterface ? !futureInterface->isPaused() : true; }
00118     virtual bool shouldThrottleThread() { return futureInterface ? futureInterface->isPaused() : false; }
00119 private:
00120     bool startThreadInternal();
00121     void startThreads();
00122     void threadExit();
00123     bool threadThrottleExit();
00124     void run();
00125     virtual void asynchronousFinish() = 0;
00126 #ifndef QT_NO_EXCEPTIONS
00127     void handleException(const QtConcurrent::Exception &exception);
00128 #endif
00129 protected:
00130     QFutureInterfaceBase *futureInterface;
00131     QThreadPool *threadPool;
00132     ThreadEngineBarrier barrier;
00133     QtConcurrent::internal::ExceptionStore exceptionStore;
00134 };
00135 
00136 
00137 template <typename T>
00138 class ThreadEngine : public virtual ThreadEngineBase
00139 {
00140 public:
00141     typedef T ResultType;
00142 
00143     virtual T *result() { return 0; }
00144 
00145     QFutureInterface<T> *futureInterfaceTyped()
00146     {
00147         return static_cast<QFutureInterface<T> *>(futureInterface);
00148     }
00149 
00150     // Runs the user algorithm using a single thread.
00151     T *startSingleThreaded()
00152     {
00153         ThreadEngineBase::startSingleThreaded();
00154         return result();
00155     }
00156 
00157     // Runs the user algorithm using multiple threads.
00158     // This function blocks until the algorithm is finished,
00159     // and then returns the result.
00160     T *startBlocking()
00161     {
00162         ThreadEngineBase::startBlocking();
00163         return result();
00164     }
00165 
00166     // Runs the user algorithm using multiple threads.
00167     // Does not block, returns a future.
00168     QFuture<T> startAsynchronously()
00169     {
00170         futureInterface = new QFutureInterface<T>();
00171 
00172         // reportStart() must be called before starting threads, otherwise the
00173         // user algorithm might finish while reportStart() is running, which
00174         // is very bad.
00175         futureInterface->reportStarted();
00176         QFuture<T> future = QFuture<T>(futureInterfaceTyped());
00177         start();
00178 
00179         acquireBarrierSemaphore();
00180         threadPool->start(this);
00181         return future;
00182     }
00183 
00184     void asynchronousFinish()
00185     {
00186         finish();
00187         futureInterfaceTyped()->reportFinished(result());
00188         delete futureInterfaceTyped();
00189         delete this;
00190     }
00191 
00192 
00193     void reportResult(const T *_result, int index = -1)
00194     {
00195         if (futureInterface)
00196             futureInterfaceTyped()->reportResult(_result, index);
00197     }
00198 
00199     void reportResults(const QVector<T> &_result, int index = -1, int count = -1)
00200     {
00201         if (futureInterface)
00202             futureInterfaceTyped()->reportResults(_result, index, count);
00203     }
00204 };
00205 
00206 // The ThreadEngineStarter class ecapsulates the return type
00207 // from the thread engine.
00208 // Depending on how the it is used, it will run
00209 // the engine in either blocking mode or asynchronous mode.
00210 template <typename T>
00211 class ThreadEngineStarterBase
00212 {
00213 public:
00214     ThreadEngineStarterBase(ThreadEngine<T> *_threadEngine)
00215     : threadEngine(_threadEngine) { }
00216 
00217     inline ThreadEngineStarterBase(const ThreadEngineStarterBase &other)
00218     : threadEngine(other.threadEngine) { }
00219 
00220     QFuture<T> startAsynchronously()
00221     {
00222         return threadEngine->startAsynchronously();
00223     }
00224 
00225     operator QFuture<T>()
00226     {
00227         return startAsynchronously();
00228     }
00229 
00230 protected:
00231     ThreadEngine<T> *threadEngine;
00232 };
00233 
00234 
00235 // We need to factor out the code that dereferences the T pointer,
00236 // with a specialization where T is void. (code that dereferences a void *
00237 // won't compile)
00238 template <typename T>
00239 class ThreadEngineStarter : public ThreadEngineStarterBase<T>
00240 {
00241     typedef ThreadEngineStarterBase<T> Base;
00242     typedef ThreadEngine<T> TypedThreadEngine;
00243 public:
00244     ThreadEngineStarter(TypedThreadEngine *eng)
00245         : Base(eng) { }
00246 
00247     T startBlocking()
00248     {
00249         T t = *this->threadEngine->startBlocking();
00250         delete this->threadEngine;
00251         return t;
00252     }
00253 };
00254 
00255 // Full template specialization where T is void.
00256 template <>
00257 class ThreadEngineStarter<void> : public ThreadEngineStarterBase<void>
00258 {
00259 public:
00260     ThreadEngineStarter<void>(ThreadEngine<void> *_threadEngine)
00261     :ThreadEngineStarterBase<void>(_threadEngine) {}
00262 
00263     void startBlocking()
00264     {
00265         this->threadEngine->startBlocking();
00266         delete this->threadEngine;
00267     }
00268 };
00269 
00270 template <typename ThreadEngine>
00271 inline ThreadEngineStarter<typename ThreadEngine::ResultType> startThreadEngine(ThreadEngine *threadEngine)
00272 {
00273     return ThreadEngineStarter<typename ThreadEngine::ResultType>(threadEngine);
00274 }
00275 
00276 } // namespace QtConcurrent
00277 
00278 #endif //qdoc
00279 
00280 QT_END_NAMESPACE
00281 QT_END_HEADER
00282 
00283 #endif // QT_NO_CONCURRENT
00284 
00285 #endif