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