Qt 6.x
The Qt SDK
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#include <QtCore/private/qsimd_p.h>
7
8#if !defined(QT_NO_CONCURRENT) || defined(Q_QDOC)
9
11
12namespace QtConcurrent {
13
55:count(0) { }
56
58{
59 forever {
60 int localCount = count.loadRelaxed();
61 if (localCount < 0) {
62 if (count.testAndSetOrdered(localCount, localCount -1))
63 return;
64 } else {
65 if (count.testAndSetOrdered(localCount, localCount + 1))
66 return;
67 }
68 qYieldCpu();
69 }
70}
71
73{
74 forever {
75 int localCount = count.loadRelaxed();
76 if (localCount == -1) {
77 if (count.testAndSetOrdered(-1, 0)) {
78 semaphore.release();
79 return 0;
80 }
81 } else if (localCount < 0) {
82 if (count.testAndSetOrdered(localCount, localCount + 1))
83 return qAbs(localCount + 1);
84 } else {
85 if (count.testAndSetOrdered(localCount, localCount - 1))
86 return localCount - 1;
87 }
88 qYieldCpu();
89 }
90}
91
92// Wait until all threads have been released
94{
95 forever {
96 int localCount = count.loadRelaxed();
97 if (localCount == 0)
98 return;
99
100 Q_ASSERT(localCount > 0); // multiple waiters are not allowed.
101 if (count.testAndSetOrdered(localCount, -localCount)) {
102 semaphore.acquire();
103 return;
104 }
105 qYieldCpu();
106 }
107}
108
110{
111 return count.loadRelaxed();
112}
113
114// releases a thread, unless this is the last thread.
115// returns true if the thread was released.
117{
118 forever {
119 int localCount = count.loadRelaxed();
120 if (qAbs(localCount) == 1) {
121 return false;
122 } else if (localCount < 0) {
123 if (count.testAndSetOrdered(localCount, localCount + 1))
124 return true;
125 } else {
126 if (count.testAndSetOrdered(localCount, localCount - 1))
127 return true;
128 }
129 qYieldCpu();
130 }
131}
132
134 : futureInterface(nullptr), threadPool(pool)
135{
136 setAutoDelete(false);
137}
138
140
142{
143 start();
144 while (threadFunction() != ThreadFinished)
145 ;
146 finish();
147}
148
150{
151 startThreadInternal();
152}
153
155{
157}
158
160{
163}
164
166{
167 if (futureInterface)
168 return futureInterface->isCanceled();
169 else
170 return false;
171}
172
174{
175 if (futureInterface)
177}
178
180{
181 // If we don't have a QFuture, there is no-one to report the progress to.
182 return (futureInterface != nullptr);
183}
184
186{
187 if (futureInterface)
189}
190
191void ThreadEngineBase::setProgressRange(int minimum, int maximum)
192{
193 if (futureInterface)
194 futureInterface->setProgressRange(minimum, maximum);
195}
196
197bool ThreadEngineBase::startThreadInternal()
198{
199 if (this->isCanceled())
200 return false;
201
203 if (!threadPool->tryStart(this)) {
205 return false;
206 }
207 return true;
208}
209
210void ThreadEngineBase::startThreads()
211{
212 while (shouldStartThread() && startThreadInternal())
213 ;
214}
215
216void ThreadEngineBase::threadExit()
217{
218 const bool asynchronous = (futureInterface != nullptr);
219 const int lastThread = (barrier.release() == 0);
220
221 if (lastThread && asynchronous)
222 this->asynchronousFinish();
223}
224
225// Called by a worker thread that wants to be throttled. If the current number
226// of running threads is larger than one the thread is allowed to exit and
227// this function returns one.
228bool ThreadEngineBase::threadThrottleExit()
229{
230 return barrier.releaseUnlessLast();
231}
232
233void ThreadEngineBase::run() // implements QRunnable.
234{
235 if (this->isCanceled()) {
236 threadExit();
237 return;
238 }
239
240 startThreads();
241
242#ifndef QT_NO_EXCEPTIONS
243 try {
244#endif
245 while (threadFunction() == ThrottleThread) {
246 // threadFunction returning ThrottleThread means it that the user
247 // struct wants to be throttled by making a worker thread exit.
248 // Respect that request unless this is the only worker thread left
249 // running, in which case it has to keep going.
250 if (threadThrottleExit()) {
251 return;
252 } else {
253 // If the last worker thread is throttled and the state is "suspending",
254 // it means that suspension has been requested, and it is already
255 // in effect (because all previous threads have already exited).
256 // Report the "Suspended" state.
258 }
259 }
260
261#ifndef QT_NO_EXCEPTIONS
262 } catch (QException &e) {
263 handleException(e);
264 } catch (...) {
265 handleException(QUnhandledException(std::current_exception()));
266 }
267#endif
268 threadExit();
269}
270
271#ifndef QT_NO_EXCEPTIONS
272
273void ThreadEngineBase::handleException(const QException &exception)
274{
275 if (futureInterface) {
277 } else {
280 exceptionStore.setException(exception);
281 }
282}
283#endif
284
285
286} // namespace QtConcurrent
287
289
290#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:317
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:20
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)
double 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
static void qYieldCpu()
Definition qsimd_p.h:403
QObject::connect nullptr
QReadWriteLock lock
[0]