Qt 4.8
qtconcurrentthreadengine.cpp
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 
43 
44 #ifndef QT_NO_CONCURRENT
45 
47 
48 namespace QtConcurrent {
49 
50 ThreadEngineBarrier::ThreadEngineBarrier()
51 :count(0) { }
52 
53 void ThreadEngineBarrier::acquire()
54 {
55  forever {
56  int localCount = int(count);
57  if (localCount < 0) {
58  if (count.testAndSetOrdered(localCount, localCount -1))
59  return;
60  } else {
61  if (count.testAndSetOrdered(localCount, localCount + 1))
62  return;
63  }
64  }
65 }
66 
67 int ThreadEngineBarrier::release()
68 {
69  forever {
70  int localCount = int(count);
71  if (localCount == -1) {
72  if (count.testAndSetOrdered(-1, 0)) {
73  semaphore.release();
74  return 0;
75  }
76  } else if (localCount < 0) {
77  if (count.testAndSetOrdered(localCount, localCount + 1))
78  return qAbs(localCount + 1);
79  } else {
80  if (count.testAndSetOrdered(localCount, localCount - 1))
81  return localCount - 1;
82  }
83  }
84 }
85 
86 // Wait until all threads have been released
87 void ThreadEngineBarrier::wait()
88 {
89  forever {
90  int localCount = int(count);
91  if (localCount == 0)
92  return;
93 
94  Q_ASSERT(localCount > 0); // multiple waiters are not allowed.
95  if (count.testAndSetOrdered(localCount, -localCount)) {
96  semaphore.acquire();
97  return;
98  }
99  }
100 }
101 
102 int ThreadEngineBarrier::currentCount()
103 {
104  return int(count);
105 }
106 
107 // releases a thread, unless this is the last thread.
108 // returns true if the thread was released.
109 bool ThreadEngineBarrier::releaseUnlessLast()
110 {
111  forever {
112  int localCount = int(count);
113  if (qAbs(localCount) == 1) {
114  return false;
115  } else if (localCount < 0) {
116  if (count.testAndSetOrdered(localCount, localCount + 1))
117  return true;
118  } else {
119  if (count.testAndSetOrdered(localCount, localCount - 1))
120  return true;
121  }
122  }
123 }
124 
125 ThreadEngineBase::ThreadEngineBase()
126 :futureInterface(0), threadPool(QThreadPool::globalInstance())
127 {
128  setAutoDelete(false);
129 }
130 
131 ThreadEngineBase::~ThreadEngineBase() {}
132 
133 void ThreadEngineBase::startSingleThreaded()
134 {
135  start();
136  while (threadFunction() != ThreadFinished)
137  ;
138  finish();
139 }
140 
141 void ThreadEngineBase::startBlocking()
142 {
143  start();
144  barrier.acquire();
145  startThreads();
146 
147  bool throttled = false;
148 #ifndef QT_NO_EXCEPTIONS
149  try {
150 #endif
151  while (threadFunction() == ThrottleThread) {
152  if (threadThrottleExit()) {
153  throttled = true;
154  break;
155  }
156  }
157 #ifndef QT_NO_EXCEPTIONS
158  } catch (QtConcurrent::Exception &e) {
159  handleException(e);
160  } catch (...) {
161  handleException(QtConcurrent::UnhandledException());
162  }
163 #endif
164 
165  if (throttled == false) {
166  barrier.release();
167  }
168 
169  barrier.wait();
170  finish();
171  exceptionStore.throwPossibleException();
172 }
173 
174 void ThreadEngineBase::startThread()
175 {
176  startThreadInternal();
177 }
178 
179 void ThreadEngineBase::acquireBarrierSemaphore()
180 {
181  barrier.acquire();
182 }
183 
184 bool ThreadEngineBase::isCanceled()
185 {
186  if (futureInterface)
187  return futureInterface->isCanceled();
188  else
189  return false;
190 }
191 
192 void ThreadEngineBase::waitForResume()
193 {
194  if (futureInterface)
195  futureInterface->waitForResume();
196 }
197 
198 bool ThreadEngineBase::isProgressReportingEnabled()
199 {
200  // If we don't have a QFuture, there is no-one to report the progress to.
201  return (futureInterface != 0);
202 }
203 
204 void ThreadEngineBase::setProgressValue(int progress)
205 {
206  if (futureInterface)
207  futureInterface->setProgressValue(progress);
208 }
209 
210 void ThreadEngineBase::setProgressRange(int minimum, int maximum)
211 {
212  if (futureInterface)
213  futureInterface->setProgressRange(minimum, maximum);
214 }
215 
216 bool ThreadEngineBase::startThreadInternal()
217 {
218  if (this->isCanceled())
219  return false;
220 
221  barrier.acquire();
222  if (!threadPool->tryStart(this)) {
223  barrier.release();
224  return false;
225  }
226  return true;
227 }
228 
229 void ThreadEngineBase::startThreads()
230 {
231  while (shouldStartThread() && startThreadInternal())
232  ;
233 }
234 
235 void ThreadEngineBase::threadExit()
236 {
237  const bool asynchronous = futureInterface != 0;
238  const int lastThread = (barrier.release() == 0);
239 
240  if (lastThread && asynchronous)
241  this->asynchronousFinish();
242 }
243 
244 // Called by a worker thread that wants to be throttled. If the current number
245 // of running threads is larger than one the thread is allowed to exit and
246 // this function returns one.
247 bool ThreadEngineBase::threadThrottleExit()
248 {
249  return barrier.releaseUnlessLast();
250 }
251 
252 void ThreadEngineBase::run() // implements QRunnable.
253 {
254  if (this->isCanceled()) {
255  threadExit();
256  return;
257  }
258 
259  startThreads();
260 
261 #ifndef QT_NO_EXCEPTIONS
262  try {
263 #endif
264  while (threadFunction() == ThrottleThread) {
265  // threadFunction returning ThrottleThread means it that the user
266  // struct wants to be throttled by making a worker thread exit.
267  // Respect that request unless this is the only worker thread left
268  // running, in which case it has to keep going.
269  if (threadThrottleExit())
270  return;
271  }
272 
273 #ifndef QT_NO_EXCEPTIONS
274  } catch (QtConcurrent::Exception &e) {
275  handleException(e);
276  } catch (...) {
277  handleException(QtConcurrent::UnhandledException());
278  }
279 #endif
280  threadExit();
281 }
282 
283 #ifndef QT_NO_EXCEPTIONS
284 
285 void ThreadEngineBase::handleException(const QtConcurrent::Exception &exception)
286 {
287  if (futureInterface)
288  futureInterface->reportException(exception);
289  else
290  exceptionStore.setException(exception);
291 }
292 #endif
293 
294 
295 } // namepsace QtConcurrent
296 
298 
299 #endif // QT_NO_CONCURRENT
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
The UnhandledException class represents an unhandled exception in a worker thread.
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
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 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...
QFuture< T > run(Function function,...)
#define forever
This macro is provided for convenience for writing infinite loops.
Definition: qglobal.h:2452