QtBase  v6.3.1
tst_qtconcurrentiteratekernel.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 #include <QThread>
29 
31 {
33  :i(i) { }
34 
36  {
37  return i - other.i;
38  }
39 
41  {
42  ++i;
43  return *this;
44  }
45 
46  bool operator!=(const TestIterator &other) const
47  {
48  return i != other.i;
49  }
50 
51  int i;
52 };
53 
54 #include <qiterator.h>
55 namespace std {
56 template <>
57 struct iterator_traits<TestIterator>
58 {
59  typedef random_access_iterator_tag iterator_category;
60 };
61 
63 {
64  return b - a;
65 }
66 
67 }
68 
70 #include <QTest>
71 
72 using namespace QtConcurrent;
73 
74 class tst_QtConcurrentIterateKernel: public QObject
75 {
76  Q_OBJECT
77 private slots:
78  // "for" iteration tests:
79  void instantiate();
80  void cancel();
81  void stresstest();
82  void noIterations();
83  void throttling();
84  void multipleResults();
85 };
86 
88 class PrintFor : public IterateKernel<TestIterator, void>
89 {
90 public:
92  bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) override
93  {
95 #ifdef PRINT
96  qDebug() << QThread::currentThread() << "iteration" << begin << "to" << end << "(exclusive)";
97 #endif
98  return false;
99  }
100  bool runIteration(TestIterator it, int index , void *result) override
101  {
102  return runIterations(it, index, index + 1, result);
103  }
104 
105 };
106 
107 class SleepPrintFor : public IterateKernel<TestIterator, void>
108 {
109 public:
111  inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) override
112  {
113  QTest::qSleep(200);
115 #ifdef PRINT
116  qDebug() << QThread::currentThread() << "iteration" << begin << "to" << end << "(exclusive)";
117 #endif
118  return false;
119  }
120  bool runIteration(TestIterator it, int index , void *result) override
121  {
122  return runIterations(it, index, index + 1, result);
123  }
124 };
125 
126 
127 void tst_QtConcurrentIterateKernel::instantiate()
128 {
129  auto future = startThreadEngine(new PrintFor(0, 40)).startAsynchronously();
132 }
133 
134 void tst_QtConcurrentIterateKernel::cancel()
135 {
136  {
137  QFuture<void> f = startThreadEngine(new SleepPrintFor(0, 40)).startAsynchronously();
138  f.cancel();
139  f.waitForFinished();
140  QVERIFY(f.isCanceled());
141  // the threads might run one iteration each before they are canceled.
144  }
145 }
146 
148 class CountFor : public IterateKernel<TestIterator, void>
149 {
150 public:
152  inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) override
153  {
154  counter.fetchAndAddRelaxed(end - begin);
155  return false;
156  }
157  bool runIteration(TestIterator it, int index , void *result) override
158  {
159  return runIterations(it, index, index + 1, result);
160  }
161 };
162 
163 void tst_QtConcurrentIterateKernel::stresstest()
164 {
165  const int iterations = 1000;
166  const int times = 50;
167  for (int i = 0; i < times; ++i) {
169  // ThreadEngine will delete f when it finishes
170  auto f = new CountFor(0, iterations);
171  auto future = f->startAsynchronously();
173  QCOMPARE(counter.loadRelaxed(), iterations);
174  }
175 }
176 
177 void tst_QtConcurrentIterateKernel::noIterations()
178 {
179  const int times = 20000;
180  for (int i = 0; i < times; ++i) {
183  .startAsynchronously();
185  }
186 }
187 
190 class ThrottleFor : public IterateKernel<TestIterator, void>
191 {
192 public:
193  // this class throttles between iterations 100 and 200,
194  // and then records how many threads that run between
195  // iterations 140 and 160.
197  inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) override
198  {
199  if (200 >= begin && 200 < end) {
200  throttling = false;
201  }
202 
204 
205  QThread *thread = QThread::currentThread();
206 
207  if (begin > 140 && end < 160) {
208  QMutexLocker locker(&threadsMutex);
209  threads.insert(thread);
210  }
211 
212  if (100 >= begin && 100 < end) {
213  throttling = true;
214  }
215 
216  QTest::qWait(1);
217 
218  return false;
219  }
220  bool runIteration(TestIterator it, int index , void *result) override
221  {
222  return runIterations(it, index, index + 1, result);
223  }
224 
225  bool shouldThrottleThread() override
226  {
227  const int load = iterations.loadRelaxed();
228  return (load > 100 && load < 200);
229  }
231 };
232 
233 void tst_QtConcurrentIterateKernel::throttling()
234 {
235  const int totalIterations = 400;
237 
238  threads.clear();
239 
240  // ThreadEngine will delete f when it finishes
241  auto f = new ThrottleFor(0, totalIterations);
242  auto future = f->startAsynchronously();
244 
245  QCOMPARE(iterations.loadRelaxed(), totalIterations);
246 
247 
248  QCOMPARE(threads.count(), 1);
249 }
250 
251 class MultipleResultsFor : public IterateKernel<TestIterator, int>
252 {
253 public:
255  inline bool runIterations(TestIterator, int begin, int end, int *results) override
256  {
257  for (int i = begin; i < end; ++i)
258  results[i - begin] = i;
259  return true;
260  }
261 };
262 
263 void tst_QtConcurrentIterateKernel::multipleResults()
264 {
265  QFuture<int> f = startThreadEngine(new MultipleResultsFor(0, 10)).startAsynchronously();
266  QCOMPARE(f.results().count() , 10);
267  QCOMPARE(f.resultAt(0), 0);
268  QCOMPARE(f.resultAt(5), 5);
269  QCOMPARE(f.resultAt(9), 9);
270  f.waitForFinished();
271 }
272 
274 
275 #include "tst_qtconcurrentiteratekernel.moc"
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
bool runIterations(TestIterator, int begin, int end, void *) override
bool runIteration(TestIterator it, int index, void *result) override
CountFor(TestIterator begin, TestIterator end)
MultipleResultsFor(TestIterator begin, TestIterator end)
bool runIterations(TestIterator, int begin, int end, int *results) override
bool runIteration(TestIterator it, int index, void *result) override
PrintFor(TestIterator begin, TestIterator end)
bool runIterations(TestIterator, int begin, int end, void *) override
The QAtomicInt class provides platform-independent atomic operations on int.
Definition: qatomic.h:158
void storeRelaxed(T newValue) noexcept
Definition: qbasicatomic.h:91
T fetchAndAddRelaxed(T valueToAdd) noexcept
Definition: qbasicatomic.h:140
T loadRelaxed() const noexcept
Definition: qbasicatomic.h:90
static QByteArray number(int, int base=10)
void waitForFinished()
Definition: qfuture.h:138
The QMutex class provides access serialization between threads.
Definition: qmutex.h:285
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes.
Definition: qmutex.h:317
Definition: qset.h:54
static int idealThreadCount() noexcept
Definition: qthread.cpp:884
static QThread * currentThread()
Definition: qthread.cpp:879
The QThreadPool class manages a collection of QThreads.
Definition: qthreadpool.h:56
static QThreadPool * globalInstance()
bool runIteration(TestIterator it, int index, void *result) override
SleepPrintFor(TestIterator begin, TestIterator end)
bool runIterations(TestIterator, int begin, int end, void *) override
bool runIteration(TestIterator it, int index, void *result) override
bool shouldThrottleThread() override
ThrottleFor(TestIterator begin, TestIterator end)
bool runIterations(TestIterator, int begin, int end, void *) override
p1 load("image.bmp")
QCOMPARE(spy.count(), 1)
Q_CORE_EXPORT void qSleep(int ms)
Q_CORE_EXPORT void qWait(int ms)
The QtConcurrent namespace provides high-level APIs that make it possible to write multi-threaded pro...
Definition: qtaskbuilder.h:81
ThreadEngineStarter< typename ThreadEngine::ResultType > startThreadEngine(ThreadEngine *threadEngine)
[qtconcurrentthreadengine-1]
Definition: qfloat16.h:381
int distance(TestIterator &a, TestIterator &b)
void
Definition: png.h:1080
#define qDebug
[1]
Definition: qlogging.h:177
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLuint GLuint end
GLfloat GLfloat f
GLuint counter
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
#define QTEST_MAIN(TestObject)
Definition: qtest.h:664
#define QVERIFY(statement)
Definition: qtestcase.h:64
#define QVERIFY2(statement, description)
Definition: qtestcase.h:76
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define slots
Definition: qtmetamacros.h:76
QList< int > results
QFuture< void > future
[5]
future cancel()
QSharedPointer< T > other(t)
[5]
QStringList::Iterator it
int operator-(const TestIterator &other)
bool operator!=(const TestIterator &other) const
QSet< QThread * > threads
QAtomicInt iterations
QAtomicInt counter