Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 09:08:55

0001 // Copyright (C) 2016 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #ifndef QTCONCURRENT_THREADENGINE_H
0005 #define QTCONCURRENT_THREADENGINE_H
0006 
0007 #include <QtConcurrent/qtconcurrent_global.h>
0008 
0009 #if !defined(QT_NO_CONCURRENT) ||defined(Q_QDOC)
0010 
0011 #include <QtCore/qthreadpool.h>
0012 #include <QtCore/qfuture.h>
0013 #include <QtCore/qexception.h>
0014 #include <QtCore/qwaitcondition.h>
0015 #include <QtCore/qatomic.h>
0016 #include <QtCore/qsemaphore.h>
0017 
0018 QT_BEGIN_NAMESPACE
0019 
0020 
0021 namespace QtConcurrent {
0022 
0023 // The ThreadEngineBarrier counts worker threads, and allows one
0024 // thread to wait for all others to finish. Tested for its use in
0025 // QtConcurrent, requires more testing for use as a general class.
0026 class ThreadEngineBarrier
0027 {
0028 private:
0029     // The thread count is maintained as an integer in the count atomic
0030     // variable. The count can be either positive or negative - a negative
0031     // count signals that a thread is waiting on the barrier.
0032 
0033     QAtomicInt count;
0034     QSemaphore semaphore;
0035 public:
0036     ThreadEngineBarrier();
0037     void acquire();
0038     int release();
0039     void wait();
0040     int currentCount();
0041     bool releaseUnlessLast();
0042 };
0043 
0044 enum ThreadFunctionResult { ThrottleThread, ThreadFinished };
0045 
0046 // The ThreadEngine controls the threads used in the computation.
0047 // Can be run in three modes: single threaded, multi-threaded blocking
0048 // and multi-threaded asynchronous.
0049 // The code for the single threaded mode is
0050 class Q_CONCURRENT_EXPORT ThreadEngineBase: public QRunnable
0051 {
0052 public:
0053     // Public API:
0054     ThreadEngineBase(QThreadPool *pool);
0055     virtual ~ThreadEngineBase();
0056     void startSingleThreaded();
0057     void startThread();
0058     bool isCanceled();
0059     void waitForResume();
0060     bool isProgressReportingEnabled();
0061     void setProgressValue(int progress);
0062     void setProgressRange(int minimum, int maximum);
0063     void acquireBarrierSemaphore();
0064     void reportIfSuspensionDone() const;
0065 
0066 protected: // The user overrides these:
0067     virtual void start() {}
0068     virtual void finish() {}
0069     virtual ThreadFunctionResult threadFunction() { return ThreadFinished; }
0070     virtual bool shouldStartThread() { return !shouldThrottleThread(); }
0071     virtual bool shouldThrottleThread()
0072     {
0073         return futureInterface ? (futureInterface->isSuspending() || futureInterface->isSuspended())
0074                                : false;
0075     }
0076 
0077 private:
0078     bool startThreadInternal();
0079     void startThreads();
0080     void threadExit();
0081     bool threadThrottleExit();
0082     void run() override;
0083     virtual void asynchronousFinish() = 0;
0084 #ifndef QT_NO_EXCEPTIONS
0085     void handleException(const QException &exception);
0086 #endif
0087 protected:
0088     QFutureInterfaceBase *futureInterface;
0089     QThreadPool *threadPool;
0090     ThreadEngineBarrier barrier;
0091     QtPrivate::ExceptionStore exceptionStore;
0092     QBasicMutex mutex;
0093 };
0094 
0095 
0096 template <typename T>
0097 class ThreadEngine : public ThreadEngineBase
0098 {
0099 public:
0100     typedef T ResultType;
0101 
0102     ThreadEngine(QThreadPool *pool) : ThreadEngineBase(pool) {}
0103 
0104     virtual T *result() { return nullptr; }
0105 
0106     QFutureInterface<T> *futureInterfaceTyped()
0107     {
0108         return static_cast<QFutureInterface<T> *>(futureInterface);
0109     }
0110 
0111     // Runs the user algorithm using a single thread.
0112     T *startSingleThreaded()
0113     {
0114         ThreadEngineBase::startSingleThreaded();
0115         return result();
0116     }
0117 
0118     // Runs the user algorithm using multiple threads.
0119     // Does not block, returns a future.
0120     QFuture<T> startAsynchronously()
0121     {
0122         futureInterface = new QFutureInterface<T>();
0123 
0124         // reportStart() must be called before starting threads, otherwise the
0125         // user algorithm might finish while reportStart() is running, which
0126         // is very bad.
0127         futureInterface->reportStarted();
0128         QFuture<T> future = QFuture<T>(futureInterfaceTyped());
0129         start();
0130 
0131         acquireBarrierSemaphore();
0132         threadPool->start(this);
0133         return future;
0134     }
0135 
0136     void asynchronousFinish() override
0137     {
0138         finish();
0139         futureInterfaceTyped()->reportFinished(result());
0140         delete futureInterfaceTyped();
0141         delete this;
0142     }
0143 
0144 
0145     void reportResult(const T *_result, int index = -1)
0146     {
0147         if (futureInterface)
0148             futureInterfaceTyped()->reportResult(_result, index);
0149     }
0150 
0151     void reportResults(const QList<T> &_result, int index = -1, int count = -1)
0152     {
0153         if (futureInterface)
0154             futureInterfaceTyped()->reportResults(_result, index, count);
0155     }
0156 };
0157 
0158 // The ThreadEngineStarter class ecapsulates the return type
0159 // from the thread engine.
0160 // Depending on how the it is used, it will run
0161 // the engine in either blocking mode or asynchronous mode.
0162 template <typename T>
0163 class ThreadEngineStarterBase
0164 {
0165 public:
0166     ThreadEngineStarterBase(ThreadEngine<T> *_threadEngine)
0167     : threadEngine(_threadEngine) { }
0168 
0169     inline ThreadEngineStarterBase(const ThreadEngineStarterBase &other)
0170     : threadEngine(other.threadEngine) { }
0171 
0172     QFuture<T> startAsynchronously()
0173     {
0174         return threadEngine->startAsynchronously();
0175     }
0176 
0177     operator QFuture<T>()
0178     {
0179         return startAsynchronously();
0180     }
0181 
0182 protected:
0183     ThreadEngine<T> *threadEngine;
0184 };
0185 
0186 
0187 // We need to factor out the code that dereferences the T pointer,
0188 // with a specialization where T is void. (code that dereferences a void *
0189 // won't compile)
0190 template <typename T>
0191 class ThreadEngineStarter : public ThreadEngineStarterBase<T>
0192 {
0193     typedef ThreadEngineStarterBase<T> Base;
0194     typedef ThreadEngine<T> TypedThreadEngine;
0195 public:
0196     ThreadEngineStarter(TypedThreadEngine *eng)
0197         : Base(eng) { }
0198 };
0199 
0200 // Full template specialization where T is void.
0201 template <>
0202 class ThreadEngineStarter<void> : public ThreadEngineStarterBase<void>
0203 {
0204 public:
0205     ThreadEngineStarter(ThreadEngine<void> *_threadEngine)
0206         : ThreadEngineStarterBase<void>(_threadEngine) {}
0207 };
0208 
0209 //! [qtconcurrentthreadengine-1]
0210 template <typename ThreadEngine>
0211 inline ThreadEngineStarter<typename ThreadEngine::ResultType> startThreadEngine(ThreadEngine *threadEngine)
0212 {
0213     return ThreadEngineStarter<typename ThreadEngine::ResultType>(threadEngine);
0214 }
0215 
0216 } // namespace QtConcurrent
0217 
0218 
0219 QT_END_NAMESPACE
0220 
0221 #endif // QT_NO_CONCURRENT
0222 
0223 #endif