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
125 // reportStart() must be called before starting threads, otherwise the
126 // user algorithm might finish while reportStart() is running, which
127 // is very bad.
128 futureInterface->reportStarted();
129 QFuture<T> future = QFuture<T>(futureInterfaceTyped());
130 start();
131
132 acquireBarrierSemaphore();
133 threadPool->start(this);
134 return future;
135 }
136
138 {
139 finish();
140 futureInterfaceTyped()->reportFinished(result());
141 delete futureInterfaceTyped();
142 delete this;
143 }
144
145
146 void reportResult(const T *_result, int index = -1)
147 {
148 if (futureInterface)
149 futureInterfaceTyped()->reportResult(_result, index);
150 }
151
152 void reportResults(const QList<T> &_result, int index = -1, int count = -1)
153 {
154 if (futureInterface)
155 futureInterfaceTyped()->reportResults(_result, index, count);
156 }
157};
158
159// The ThreadEngineStarter class ecapsulates the return type
160// from the thread engine.
161// Depending on how the it is used, it will run
162// the engine in either blocking mode or asynchronous mode.
163template <typename T>
165{
166public:
169
172
174 {
175 return threadEngine->startAsynchronously();
176 }
177
179 {
180 return startAsynchronously();
181 }
182
183protected:
185};
186
187
188// We need to factor out the code that dereferences the T pointer,
189// with a specialization where T is void. (code that dereferences a void *
190// won't compile)
191template <typename T>
193{
194 typedef ThreadEngineStarterBase<T> Base;
195 typedef ThreadEngine<T> TypedThreadEngine;
196public:
197 ThreadEngineStarter(TypedThreadEngine *eng)
198 : Base(eng) { }
199};
200
201// Full template specialization where T is void.
202template <>
204{
205public:
208};
209
210//! [qtconcurrentthreadengine-1]
211template <typename ThreadEngine>
212inline ThreadEngineStarter<typename ThreadEngine::ResultType> startThreadEngine(ThreadEngine *threadEngine)
213{
214 return ThreadEngineStarter<typename ThreadEngine::ResultType>(threadEngine);
215}
216
217} // namespace QtConcurrent
218
219
220QT_END_NAMESPACE
221
222#endif // QT_NO_CONCURRENT
223
224#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)
\inmodule QtConcurrent
ThreadEngineStarter< typename ThreadEngine::ResultType > startThreadEngine(ThreadEngine *threadEngine)
[qtconcurrentthreadengine-1]