Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qtconcurrentthreadengine.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#if !defined(QT_NO_CONCURRENT) || defined(Q_QDOC)
7
9
10namespace QtConcurrent {
11
54
56{
57 forever {
58 int localCount = count.loadRelaxed();
59 if (localCount < 0) {
60 if (count.testAndSetOrdered(localCount, localCount -1))
61 return;
62 } else {
63 if (count.testAndSetOrdered(localCount, localCount + 1))
64 return;
65 }
66 qYieldCpu();
67 }
68}
69
71{
72 forever {
73 int localCount = count.loadRelaxed();
74 if (localCount == -1) {
75 if (count.testAndSetOrdered(-1, 0)) {
76 semaphore.release();
77 return 0;
78 }
79 } else if (localCount < 0) {
80 if (count.testAndSetOrdered(localCount, localCount + 1))
81 return qAbs(localCount + 1);
82 } else {
83 if (count.testAndSetOrdered(localCount, localCount - 1))
84 return localCount - 1;
85 }
86 qYieldCpu();
87 }
88}
89
90// Wait until all threads have been released
92{
93 forever {
94 int localCount = count.loadRelaxed();
95 if (localCount == 0)
96 return;
97
98 Q_ASSERT(localCount > 0); // multiple waiters are not allowed.
99 if (count.testAndSetOrdered(localCount, -localCount)) {
100 semaphore.acquire();
101 return;
102 }
103 qYieldCpu();
104 }
105}
106
108{
109 return count.loadRelaxed();
110}
111
112// releases a thread, unless this is the last thread.
113// returns true if the thread was released.
115{
116 forever {
117 int localCount = count.loadRelaxed();
118 if (qAbs(localCount) == 1) {
119 return false;
120 } else if (localCount < 0) {
121 if (count.testAndSetOrdered(localCount, localCount + 1))
122 return true;
123 } else {
124 if (count.testAndSetOrdered(localCount, localCount - 1))
125 return true;
126 }
127 qYieldCpu();
128 }
129}
130
132 : futureInterface(nullptr), threadPool(pool)
133{
134 setAutoDelete(false);
135}
136
138
140{
141 start();
142 while (threadFunction() != ThreadFinished)
143 ;
144 finish();
145}
146
148{
149 startThreadInternal();
150}
151
156
162
164{
165 if (futureInterface)
166 return futureInterface->isCanceled();
167 else
168 return false;
169}
170
176
178{
179 // If we don't have a QFuture, there is no-one to report the progress to.
180 return (futureInterface != nullptr);
181}
182
184{
185 if (futureInterface)
187}
188
189void ThreadEngineBase::setProgressRange(int minimum, int maximum)
190{
191 if (futureInterface)
192 futureInterface->setProgressRange(minimum, maximum);
193}
194
195bool ThreadEngineBase::startThreadInternal()
196{
197 if (this->isCanceled())
198 return false;
199
201 if (!threadPool->tryStart(this)) {
203 return false;
204 }
205 return true;
206}
207
208void ThreadEngineBase::startThreads()
209{
210 while (shouldStartThread() && startThreadInternal())
211 ;
212}
213
214void ThreadEngineBase::threadExit()
215{
216 const bool asynchronous = (futureInterface != nullptr);
217 const int lastThread = (barrier.release() == 0);
218
219 if (lastThread && asynchronous)
220 this->asynchronousFinish();
221}
222
223// Called by a worker thread that wants to be throttled. If the current number
224// of running threads is larger than one the thread is allowed to exit and
225// this function returns one.
226bool ThreadEngineBase::threadThrottleExit()
227{
228 return barrier.releaseUnlessLast();
229}
230
231void ThreadEngineBase::run() // implements QRunnable.
232{
233 if (this->isCanceled()) {
234 threadExit();
235 return;
236 }
237
238 startThreads();
239
240#ifndef QT_NO_EXCEPTIONS
241 try {
242#endif
243 while (threadFunction() == ThrottleThread) {
244 // threadFunction returning ThrottleThread means it that the user
245 // struct wants to be throttled by making a worker thread exit.
246 // Respect that request unless this is the only worker thread left
247 // running, in which case it has to keep going.
248 if (threadThrottleExit()) {
249 return;
250 } else {
251 // If the last worker thread is throttled and the state is "suspending",
252 // it means that suspension has been requested, and it is already
253 // in effect (because all previous threads have already exited).
254 // Report the "Suspended" state.
256 }
257 }
258
259#ifndef QT_NO_EXCEPTIONS
260 } catch (QException &e) {
261 handleException(e);
262 } catch (...) {
263 handleException(QUnhandledException(std::current_exception()));
264 }
265#endif
266 threadExit();
267}
268
269#ifndef QT_NO_EXCEPTIONS
270
271void ThreadEngineBase::handleException(const QException &exception)
272{
273 if (futureInterface) {
275 } else {
278 exceptionStore.setException(exception);
279 }
280}
281#endif
282
283
284} // namespace QtConcurrent
285
287
288#endif // QT_NO_CONCURRENT
\inmodule QtCore
Definition qexception.h:22
void setProgressValue(int progressValue)
void setProgressRange(int minimum, int maximum)
void reportException(const QException &e)
\inmodule QtCore
Definition qmutex.h:313
void setAutoDelete(bool autoDelete)
Enables auto-deletion if autoDelete is true; otherwise auto-deletion is disabled.
Definition qrunnable.h:38
void acquire(int n=1)
Tries to acquire n resources guarded by the semaphore.
void release(int n=1)
Releases n resources guarded by the semaphore.
\inmodule QtCore
Definition qthreadpool.h:22
bool tryStart(QRunnable *runnable)
Attempts to reserve a thread to run runnable.
\inmodule QtCore
Definition qexception.h:31
void setProgressRange(int minimum, int maximum)
virtual ThreadFunctionResult threadFunction()
virtual void asynchronousFinish()=0
QtPrivate::ExceptionStore exceptionStore
void run() override
Implement this pure virtual function in your subclass.
void setException(const QException &e)
Combined button and popup list for selecting options.
\inmodule QtConcurrent
#define forever
Definition qforeach.h:78
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLenum GLenum GLsizei count
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE Q_ALWAYS_INLINE void qYieldCpu(void) Q_DECL_NOEXCEPT
Definition qyieldcpu.h:29
QObject::connect nullptr
QReadWriteLock lock
[0]