1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 
57 QT_BEGIN_HEADER
58 QT_BEGIN_NAMESPACE
59 
QT_MODULE(Core)60 QT_MODULE(Core)
61 
62 #ifndef qdoc
63 
64 namespace 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.
69 class ThreadEngineBarrier
70 {
71 private:
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;
82 public:
83     ThreadEngineBarrier();
84     void acquire();
85     int release();
86     void wait();
87     int currentCount();
88     bool releaseUnlessLast();
89 };
90 
91 enum 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
97 class Q_CORE_EXPORT ThreadEngineBase: public QRunnable
98 {
99 public:
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 
113 protected: // 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; }
119 private:
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
129 protected:
130     QFutureInterfaceBase *futureInterface;
131     QThreadPool *threadPool;
132     ThreadEngineBarrier barrier;
133     QtConcurrent::internal::ExceptionStore exceptionStore;
134 };
135 
136 
137 template <typename T>
138 class ThreadEngine : public virtual ThreadEngineBase
139 {
140 public:
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.
210 template <typename T>
211 class ThreadEngineStarterBase
212 {
213 public:
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 
230 protected:
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)
238 template <typename T>
239 class ThreadEngineStarter : public ThreadEngineStarterBase<T>
240 {
241     typedef ThreadEngineStarterBase<T> Base;
242     typedef ThreadEngine<T> TypedThreadEngine;
243 public:
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.
256 template <>
257 class ThreadEngineStarter<void> : public ThreadEngineStarterBase<void>
258 {
259 public:
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 
270 template <typename ThreadEngine>
271 inline 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 
280 QT_END_NAMESPACE
281 QT_END_HEADER
282 
283 #endif // QT_NO_CONCURRENT
284 
285 #endif
286