Qt 4.8
qtconcurrentthreadengine.h
Go to the documentation of this file.
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 
59 
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;
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 
282 
283 #endif // QT_NO_CONCURRENT
284 
285 #endif
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
The QSemaphore class provides a general counting semaphore.
Definition: qsemaphore.h:57
The QMutex class provides access serialization between threads.
Definition: qmutex.h:60
#define QT_MODULE(x)
Definition: qglobal.h:2783
#define QT_BEGIN_HEADER
Definition: qglobal.h:136
The QAtomicInt class provides platform-independent atomic operations on integers. ...
Definition: qatomic.h:55
The QVector class is a template class that provides a dynamic array.
Definition: qdatastream.h:64
The QRunnable class is the base class for all runnable objects.
Definition: qrunnable.h:52
The QThreadPool class manages a collection of QThreads.
Definition: qthreadpool.h:58
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
The QFuture class represents the result of an asynchronous computation.
Definition: qfuture.h:64
#define Q_CORE_EXPORT
Definition: qglobal.h:1449
The Exception class provides a base class for exceptions that can transferred across threads...
The QtConcurrent namespace provides high-level APIs that make it possible to write multi-threaded pro...
quint16 index
QFuture< T > run(Function function,...)
#define QT_END_HEADER
Definition: qglobal.h:137