1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QTCONCURRENT_THREADENGINE_H
43#define QTCONCURRENT_THREADENGINE_H
44
45#include <QtCore/qglobal.h>
46
47#ifndef QT_NO_CONCURRENT
48
49#include <QtCore/qthreadpool.h>
50#include <QtCore/qfuture.h>
51#include <QtCore/qdebug.h>
52#include <QtCore/qtconcurrentexception.h>
53#include <QtCore/qwaitcondition.h>
54#include <QtCore/qatomic.h>
55#include <QtCore/qsemaphore.h>
56
57QT_BEGIN_HEADER
58QT_BEGIN_NAMESPACE
59
60QT_MODULE(Core)
61
62#ifndef qdoc
63
64namespace QtConcurrent {
65
66// The ThreadEngineBarrier counts worker threads, and allows one
67// thread to wait for all others to finish. Tested for its use in
68// QtConcurrent, requires more testing for use as a general class.
69class ThreadEngineBarrier
70{
71private:
72 // The thread count is maintained as an integer in the count atomic
73 // variable. The count can be either positive or negative - a negative
74 // count signals that a thread is waiting on the barrier.
75
76 // BC note: inlined code from Qt < 4.6 will expect to find the QMutex
77 // and QAtomicInt here. ### Qt 5: remove.
78 QMutex mutex;
79 QAtomicInt count;
80
81 QSemaphore semaphore;
82public:
83 ThreadEngineBarrier();
84 void acquire();
85 int release();
86 void wait();
87 int currentCount();
88 bool releaseUnlessLast();
89};
90
91enum ThreadFunctionResult { ThrottleThread, ThreadFinished };
92
93// The ThreadEngine controls the threads used in the computation.
94// Can be run in three modes: single threaded, multi-threaded blocking
95// and multi-threaded asynchronous.
96// The code for the single threaded mode is
97class Q_CORE_EXPORT ThreadEngineBase: public QRunnable
98{
99public:
100 // Public API:
101 ThreadEngineBase();
102 virtual ~ThreadEngineBase();
103 void startSingleThreaded();
104 void startBlocking();
105 void startThread();
106 bool isCanceled();
107 void waitForResume();
108 bool isProgressReportingEnabled();
109 void setProgressValue(int progress);
110 void setProgressRange(int minimum, int maximum);
111 void acquireBarrierSemaphore();
112
113protected: // The user overrides these:
114 virtual void start() {}
115 virtual void finish() {}
116 virtual ThreadFunctionResult threadFunction() { return ThreadFinished; }
117 virtual bool shouldStartThread() { return futureInterface ? !futureInterface->isPaused() : true; }
118 virtual bool shouldThrottleThread() { return futureInterface ? futureInterface->isPaused() : false; }
119private:
120 bool startThreadInternal();
121 void startThreads();
122 void threadExit();
123 bool threadThrottleExit();
124 void run();
125 virtual void asynchronousFinish() = 0;
126#ifndef QT_NO_EXCEPTIONS
127 void handleException(const QtConcurrent::Exception &exception);
128#endif
129protected:
130 QFutureInterfaceBase *futureInterface;
131 QThreadPool *threadPool;
132 ThreadEngineBarrier barrier;
133 QtConcurrent::internal::ExceptionStore exceptionStore;
134};
135
136
137template <typename T>
138class ThreadEngine : public virtual ThreadEngineBase
139{
140public:
141 typedef T ResultType;
142
143 virtual T *result() { return 0; }
144
145 QFutureInterface<T> *futureInterfaceTyped()
146 {
147 return static_cast<QFutureInterface<T> *>(futureInterface);
148 }
149
150 // Runs the user algorithm using a single thread.
151 T *startSingleThreaded()
152 {
153 ThreadEngineBase::startSingleThreaded();
154 return result();
155 }
156
157 // Runs the user algorithm using multiple threads.
158 // This function blocks until the algorithm is finished,
159 // and then returns the result.
160 T *startBlocking()
161 {
162 ThreadEngineBase::startBlocking();
163 return result();
164 }
165
166 // Runs the user algorithm using multiple threads.
167 // Does not block, returns a future.
168 QFuture<T> startAsynchronously()
169 {
170 futureInterface = new QFutureInterface<T>();
171
172 // reportStart() must be called before starting threads, otherwise the
173 // user algorithm might finish while reportStart() is running, which
174 // is very bad.
175 futureInterface->reportStarted();
176 QFuture<T> future = QFuture<T>(futureInterfaceTyped());
177 start();
178
179 acquireBarrierSemaphore();
180 threadPool->start(this);
181 return future;
182 }
183
184 void asynchronousFinish()
185 {
186 finish();
187 futureInterfaceTyped()->reportFinished(result());
188 delete futureInterfaceTyped();
189 delete this;
190 }
191
192
193 void reportResult(const T *_result, int index = -1)
194 {
195 if (futureInterface)
196 futureInterfaceTyped()->reportResult(_result, index);
197 }
198
199 void reportResults(const QVector<T> &_result, int index = -1, int count = -1)
200 {
201 if (futureInterface)
202 futureInterfaceTyped()->reportResults(_result, index, count);
203 }
204};
205
206// The ThreadEngineStarter class ecapsulates the return type
207// from the thread engine.
208// Depending on how the it is used, it will run
209// the engine in either blocking mode or asynchronous mode.
210template <typename T>
211class ThreadEngineStarterBase
212{
213public:
214 ThreadEngineStarterBase(ThreadEngine<T> *_threadEngine)
215 : threadEngine(_threadEngine) { }
216
217 inline ThreadEngineStarterBase(const ThreadEngineStarterBase &other)
218 : threadEngine(other.threadEngine) { }
219
220 QFuture<T> startAsynchronously()
221 {
222 return threadEngine->startAsynchronously();
223 }
224
225 operator QFuture<T>()
226 {
227 return startAsynchronously();
228 }
229
230protected:
231 ThreadEngine<T> *threadEngine;
232};
233
234
235// We need to factor out the code that dereferences the T pointer,
236// with a specialization where T is void. (code that dereferences a void *
237// won't compile)
238template <typename T>
239class ThreadEngineStarter : public ThreadEngineStarterBase<T>
240{
241 typedef ThreadEngineStarterBase<T> Base;
242 typedef ThreadEngine<T> TypedThreadEngine;
243public:
244 ThreadEngineStarter(TypedThreadEngine *eng)
245 : Base(eng) { }
246
247 T startBlocking()
248 {
249 T t = *this->threadEngine->startBlocking();
250 delete this->threadEngine;
251 return t;
252 }
253};
254
255// Full template specialization where T is void.
256template <>
257class ThreadEngineStarter<void> : public ThreadEngineStarterBase<void>
258{
259public:
260 ThreadEngineStarter<void>(ThreadEngine<void> *_threadEngine)
261 :ThreadEngineStarterBase<void>(_threadEngine) {}
262
263 void startBlocking()
264 {
265 this->threadEngine->startBlocking();
266 delete this->threadEngine;
267 }
268};
269
270template <typename ThreadEngine>
271inline ThreadEngineStarter<typename ThreadEngine::ResultType> startThreadEngine(ThreadEngine *threadEngine)
272{
273 return ThreadEngineStarter<typename ThreadEngine::ResultType>(threadEngine);
274}
275
276} // namespace QtConcurrent
277
278#endif //qdoc
279
280QT_END_NAMESPACE
281QT_END_HEADER
282
283#endif // QT_NO_CONCURRENT
284
285#endif
286