File indexing completed on 2026-09-21 09:21:01
0001
0002
0003
0004
0005 #ifndef QTCONCURRENT_ITERATEKERNEL_H
0006 #define QTCONCURRENT_ITERATEKERNEL_H
0007
0008 #include <QtConcurrent/qtconcurrent_global.h>
0009
0010 #if !defined(QT_NO_CONCURRENT) || defined(Q_QDOC)
0011
0012 #include <QtCore/qatomic.h>
0013 #include <QtConcurrent/qtconcurrentmedian.h>
0014 #include <QtConcurrent/qtconcurrentthreadengine.h>
0015
0016 #include <iterator>
0017
0018 QT_BEGIN_NAMESPACE
0019
0020
0021
0022 namespace QtConcurrent {
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 class Q_CONCURRENT_EXPORT BlockSizeManager
0033 {
0034 public:
0035 explicit BlockSizeManager(QThreadPool *pool, int iterationCount);
0036
0037 void timeBeforeUser();
0038 void timeAfterUser();
0039 int blockSize();
0040
0041 private:
0042 inline bool blockSizeMaxed()
0043 {
0044 return (m_blockSize >= maxBlockSize);
0045 }
0046
0047 const int maxBlockSize;
0048 qint64 beforeUser;
0049 qint64 afterUser;
0050 Median controlPartElapsed;
0051 Median userPartElapsed;
0052 int m_blockSize;
0053
0054 Q_DISABLE_COPY(BlockSizeManager)
0055 };
0056
0057 template <typename T>
0058 class ResultReporter
0059 {
0060 public:
0061 ResultReporter(ThreadEngine<T> *_threadEngine, T &_defaultValue)
0062 : threadEngine(_threadEngine), defaultValue(_defaultValue)
0063 {
0064 }
0065
0066 void reserveSpace(int resultCount)
0067 {
0068 currentResultCount = resultCount;
0069 resizeList(qMax(resultCount, vector.size()));
0070 }
0071
0072 void reportResults(int begin)
0073 {
0074 const int useVectorThreshold = 4;
0075 if (currentResultCount > useVectorThreshold) {
0076 resizeList(currentResultCount);
0077 threadEngine->reportResults(vector, begin);
0078 } else {
0079 for (int i = 0; i < currentResultCount; ++i)
0080 threadEngine->reportResult(&vector.at(i), begin + i);
0081 }
0082 }
0083
0084 inline T * getPointer()
0085 {
0086 return vector.data();
0087 }
0088
0089 int currentResultCount = 0;
0090 ThreadEngine<T> *threadEngine;
0091 QList<T> vector;
0092
0093 private:
0094 void resizeList(qsizetype size)
0095 {
0096 if constexpr (std::is_default_constructible_v<T>)
0097 vector.resize(size);
0098 else
0099 vector.resize(size, defaultValue);
0100 }
0101
0102 T &defaultValue;
0103 };
0104
0105 template <>
0106 class ResultReporter<void>
0107 {
0108 public:
0109 inline ResultReporter(ThreadEngine<void> *) { }
0110 inline void reserveSpace(int) { }
0111 inline void reportResults(int) { }
0112 inline void * getPointer() { return nullptr; }
0113 };
0114
0115 template<typename T>
0116 struct DefaultValueContainer
0117 {
0118 template<typename U = T>
0119 DefaultValueContainer(U &&_value) : value(std::forward<U>(_value))
0120 {
0121 }
0122
0123 T value;
0124 };
0125
0126 template<>
0127 struct DefaultValueContainer<void>
0128 {
0129 };
0130
0131 inline bool selectIteration(std::bidirectional_iterator_tag)
0132 {
0133 return false;
0134 }
0135
0136 inline bool selectIteration(std::forward_iterator_tag)
0137 {
0138 return false;
0139 }
0140
0141 inline bool selectIteration(std::random_access_iterator_tag)
0142 {
0143 return true;
0144 }
0145
0146 template <typename Iterator, typename T>
0147 class IterateKernel : public ThreadEngine<T>
0148 {
0149 using IteratorCategory = typename std::iterator_traits<Iterator>::iterator_category;
0150
0151 public:
0152 typedef T ResultType;
0153
0154 template<typename U = T, std::enable_if_t<std::is_same_v<U, void>, bool> = true>
0155 IterateKernel(QThreadPool *pool, Iterator _begin, Iterator _end)
0156 : ThreadEngine<U>(pool),
0157 begin(_begin),
0158 end(_end),
0159 current(_begin),
0160 iterationCount(selectIteration(IteratorCategory()) ? static_cast<int>(std::distance(_begin, _end)) : 0),
0161 forIteration(selectIteration(IteratorCategory())),
0162 progressReportingEnabled(true)
0163 {
0164 }
0165
0166 template<typename U = T, std::enable_if_t<!std::is_same_v<U, void>, bool> = true>
0167 IterateKernel(QThreadPool *pool, Iterator _begin, Iterator _end)
0168 : ThreadEngine<U>(pool),
0169 begin(_begin),
0170 end(_end),
0171 current(_begin),
0172 iterationCount(selectIteration(IteratorCategory()) ? static_cast<int>(std::distance(_begin, _end)) : 0),
0173 forIteration(selectIteration(IteratorCategory())),
0174 progressReportingEnabled(true),
0175 defaultValue(U())
0176 {
0177 }
0178
0179 template<typename U = T, std::enable_if_t<!std::is_same_v<U, void>, bool> = true>
0180 IterateKernel(QThreadPool *pool, Iterator _begin, Iterator _end, U &&_defaultValue)
0181 : ThreadEngine<U>(pool),
0182 begin(_begin),
0183 end(_end),
0184 current(_begin),
0185 iterationCount(selectIteration(IteratorCategory()) ? static_cast<int>(std::distance(_begin, _end)) : 0),
0186 forIteration(selectIteration(IteratorCategory())),
0187 progressReportingEnabled(true),
0188 defaultValue(std::forward<U>(_defaultValue))
0189 {
0190 }
0191
0192 virtual ~IterateKernel() { }
0193
0194 virtual bool runIteration(Iterator, int , T *) { return false; }
0195 virtual bool runIterations(Iterator, int, int, T *) { return false; }
0196
0197 void start() override
0198 {
0199 progressReportingEnabled = this->isProgressReportingEnabled();
0200 if (progressReportingEnabled && iterationCount > 0)
0201 this->setProgressRange(0, iterationCount);
0202 }
0203
0204 bool shouldStartThread() override
0205 {
0206 if (forIteration)
0207 return (currentIndex.loadRelaxed() < iterationCount) && !this->shouldThrottleThread();
0208 else
0209 return (iteratorThreads.loadRelaxed() == 0);
0210 }
0211
0212 ThreadFunctionResult threadFunction() override
0213 {
0214 if (forIteration)
0215 return this->forThreadFunction();
0216 else
0217 return this->whileThreadFunction();
0218 }
0219
0220 ThreadFunctionResult forThreadFunction()
0221 {
0222 BlockSizeManager blockSizeManager(ThreadEngineBase::threadPool, iterationCount);
0223 ResultReporter<T> resultReporter = createResultsReporter();
0224
0225 for(;;) {
0226 if (this->isCanceled())
0227 break;
0228
0229 const int currentBlockSize = blockSizeManager.blockSize();
0230
0231 if (currentIndex.loadRelaxed() >= iterationCount)
0232 break;
0233
0234
0235 const int beginIndex = currentIndex.fetchAndAddRelease(currentBlockSize);
0236 const int endIndex = qMin(beginIndex + currentBlockSize, iterationCount);
0237
0238 if (beginIndex >= endIndex) {
0239
0240 break;
0241 }
0242
0243 this->waitForResume();
0244
0245 if (shouldStartThread())
0246 this->startThread();
0247
0248 const int finalBlockSize = endIndex - beginIndex;
0249 resultReporter.reserveSpace(finalBlockSize);
0250
0251
0252 blockSizeManager.timeBeforeUser();
0253 const bool resultsAvailable = this->runIterations(begin, beginIndex, endIndex, resultReporter.getPointer());
0254 blockSizeManager.timeAfterUser();
0255
0256 if (resultsAvailable)
0257 resultReporter.reportResults(beginIndex);
0258
0259
0260 if (progressReportingEnabled) {
0261 completed.fetchAndAddAcquire(finalBlockSize);
0262 this->setProgressValue(this->completed.loadRelaxed());
0263 }
0264
0265 if (this->shouldThrottleThread())
0266 return ThrottleThread;
0267 }
0268 return ThreadFinished;
0269 }
0270
0271 ThreadFunctionResult whileThreadFunction()
0272 {
0273 if (iteratorThreads.testAndSetAcquire(0, 1) == false)
0274 return ThreadFinished;
0275
0276 ResultReporter<T> resultReporter = createResultsReporter();
0277 resultReporter.reserveSpace(1);
0278
0279 while (current != end) {
0280
0281
0282
0283 Iterator prev = current;
0284 ++current;
0285 int index = currentIndex.fetchAndAddRelaxed(1);
0286 iteratorThreads.testAndSetRelease(1, 0);
0287
0288 this->waitForResume();
0289
0290 if (shouldStartThread())
0291 this->startThread();
0292
0293 const bool resultAavailable = this->runIteration(prev, index, resultReporter.getPointer());
0294 if (resultAavailable)
0295 resultReporter.reportResults(index);
0296
0297 if (this->shouldThrottleThread())
0298 return ThrottleThread;
0299
0300 if (iteratorThreads.testAndSetAcquire(0, 1) == false)
0301 return ThreadFinished;
0302 }
0303
0304 return ThreadFinished;
0305 }
0306
0307 private:
0308 ResultReporter<T> createResultsReporter()
0309 {
0310 if constexpr (!std::is_same_v<T, void>)
0311 return ResultReporter<T>(this, defaultValue.value);
0312 else
0313 return ResultReporter<T>(this);
0314 }
0315
0316 public:
0317 const Iterator begin;
0318 const Iterator end;
0319 Iterator current;
0320 QAtomicInt currentIndex;
0321 QAtomicInt iteratorThreads;
0322 QAtomicInt completed;
0323 const int iterationCount;
0324 const bool forIteration;
0325 bool progressReportingEnabled;
0326 DefaultValueContainer<ResultType> defaultValue;
0327 };
0328
0329 }
0330
0331
0332 QT_END_NAMESPACE
0333
0334 #endif
0335
0336 #endif