Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtconcurrentthreadengine.h
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// Qt-Security score:significant reason:default
4
5#ifndef QTCONCURRENT_THREADENGINE_H
6#define QTCONCURRENT_THREADENGINE_H
7
8#include <QtConcurrent/qtconcurrent_global.h>
9
10#if !defined(QT_NO_CONCURRENT) ||defined(Q_QDOC)
11
12#include <QtCore/qthreadpool.h>
13#include <QtCore/qfuture.h>
14#include <QtCore/qexception.h>
15#include <QtCore/qwaitcondition.h>
16#include <QtCore/qatomic.h>
17#include <QtCore/qsemaphore.h>
18
19QT_BEGIN_NAMESPACE
20
21
22namespace QtConcurrent {
23
24// The ThreadEngineBarrier counts worker threads, and allows one
25// thread to wait for all others to finish. Tested for its use in
26// QtConcurrent, requires more testing for use as a general class.
28{
29private:
30 // The thread count is maintained as an integer in the count atomic
31 // variable. The count can be either positive or negative - a negative
32 // count signals that a thread is waiting on the barrier.
33
34 QAtomicInt count;
35 QSemaphore semaphore;
36public:
38 void acquire();
39 int release();
40 void wait();
41 int currentCount();
42 bool releaseUnlessLast();
43};
44
46
47// The ThreadEngine controls the threads used in the computation.
48// Can be run in three modes: single threaded, multi-threaded blocking
49// and multi-threaded asynchronous.
50// The code for the single threaded mode is
51class Q_CONCURRENT_EXPORT ThreadEngineBase: public QRunnable
52{
53public:
54 // Public API:
56 virtual ~ThreadEngineBase();
58 void startThread();
59 bool isCanceled();
60 void waitForResume();
62 void setProgressValue(int progress);
63 void setProgressRange(int minimum, int maximum);
65 void reportIfSuspensionDone() const;
66
67protected: // The user overrides these:
68 virtual void start() {}
69 virtual void finish() {}
71 virtual bool shouldStartThread() { return !shouldThrottleThread(); }
72 virtual bool shouldThrottleThread()
73 {
75 : false;
76 }
77
78private:
80 void startThreads();
81 void threadExit();
82 bool threadThrottleExit();
83 void run() override;
84 virtual void asynchronousFinish() = 0;
85#ifndef QT_NO_EXCEPTIONS
87#endif
88protected:
94};
95
96
97template <typename T>
99{
100public:
101 typedef T ResultType;
102
103 ThreadEngine(QThreadPool *pool) : ThreadEngineBase(pool) {}
104
105 virtual T *result() { return nullptr; }
106
108 {
109 return static_cast<QFutureInterface<T> *>(futureInterface);
110 }
111
112 // Runs the user algorithm using a single thread.
114 {
115 ThreadEngineBase::startSingleThreaded();
116 return result();
117 }
118
119 // Runs the user algorithm using multiple threads.
120 // Does not block, returns a future.
122 {
123 futureInterface = new QFutureInterface<T>();
124 futureInterface->setThreadPool(threadPool);
125
126 // reportStart() must be called before starting threads, otherwise the
127 // user algorithm might finish while reportStart() is running, which
128 // is very bad.
129 futureInterface->reportStarted();
130 QFuture<T> future = QFuture<T>(futureInterfaceTyped());
131 start();
132
133 acquireBarrierSemaphore();
134 threadPool->start(this);
135 return future;
136 }
137
139 {
140 finish();
141 futureInterfaceTyped()->reportFinished(result());
142 delete futureInterfaceTyped();
143 delete this;
144 }
145
146
147 void reportResult(const T *_result, int index = -1)
148 {
149 if (futureInterface)
150 futureInterfaceTyped()->reportResult(_result, index);
151 }
152
153 void reportResults(const QList<T> &_result, int index = -1, int count = -1)
154 {
155 if (futureInterface)
156 futureInterfaceTyped()->reportResults(_result, index, count);
157 }
158};
159
160// The ThreadEngineStarter class ecapsulates the return type
161// from the thread engine.
162// Depending on how the it is used, it will run
163// the engine in either blocking mode or asynchronous mode.
164template <typename T>
166{
167public:
170
173
175 {
176 return threadEngine->startAsynchronously();
177 }
178
180 {
181 return startAsynchronously();
182 }
183
184protected:
186};
187
188
189// We need to factor out the code that dereferences the T pointer,
190// with a specialization where T is void. (code that dereferences a void *
191// won't compile)
192template <typename T>
194{
195 typedef ThreadEngineStarterBase<T> Base;
196 typedef ThreadEngine<T> TypedThreadEngine;
197public:
198 ThreadEngineStarter(TypedThreadEngine *eng)
199 : Base(eng) { }
200};
201
202// Full template specialization where T is void.
203template <>
205{
206public:
209};
210
211//! [qtconcurrentthreadengine-1]
212template <typename ThreadEngine>
213inline ThreadEngineStarter<typename ThreadEngine::ResultType> startThreadEngine(ThreadEngine *threadEngine)
214{
215 return ThreadEngineStarter<typename ThreadEngine::ResultType>(threadEngine);
216}
217
218} // namespace QtConcurrent
219
220
221QT_END_NAMESPACE
222
223#endif // QT_NO_CONCURRENT
224
225#endif
ThreadEngineStarterBase(ThreadEngine< T > *_threadEngine)
ThreadEngineStarterBase(const ThreadEngineStarterBase &other)
ThreadEngineStarter(ThreadEngine< void > *_threadEngine)
QFutureInterface< T > * futureInterfaceTyped()
void reportResult(const T *_result, int index=-1)
void reportResults(const QList< T > &_result, int index=-1, int count=-1)
Combined button and popup list for selecting options.
\inmodule QtConcurrent
ThreadEngineStarter< typename ThreadEngine::ResultType > startThreadEngine(ThreadEngine *threadEngine)
[qtconcurrentthreadengine-1]