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