Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-21 10:09:51

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