File indexing completed on 2024-09-15 03:52:12
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2010-04-13 0007 * Description : Dynamically active thread 0008 * 0009 * SPDX-FileCopyrightText: 2010-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #ifndef DIGIKAM_DYNAMIC_THREAD_H 0016 #define DIGIKAM_DYNAMIC_THREAD_H 0017 0018 // Qt includes 0019 0020 #include <QObject> 0021 #include <QThread> 0022 #include <QRunnable> 0023 #include <QMutex> 0024 #include <QMutexLocker> 0025 0026 // Local includes 0027 0028 #include "digikam_export.h" 0029 0030 namespace Digikam 0031 { 0032 0033 class DIGIKAM_EXPORT DynamicThread : public QObject 0034 { 0035 Q_OBJECT 0036 0037 public: 0038 0039 enum State 0040 { 0041 Inactive, 0042 Scheduled, 0043 Running, 0044 Deactivating 0045 }; 0046 0047 public: 0048 0049 /** 0050 * This class extends QRunnable, so you have to reimplement 0051 * virtual void run(). In all aspects the class will act similar to a QThread. 0052 */ 0053 explicit DynamicThread(QObject* const parent = nullptr); 0054 0055 /** 0056 * The destructor calls stop() and wait(), but if you, in your destructor, 0057 * delete any data that is accessed by your run() method, 0058 * you must call stop() and wait() before yourself. 0059 */ 0060 ~DynamicThread() override; 0061 0062 /** 0063 * Implement this pure virtual function in your subclass. 0064 */ 0065 virtual void run() = 0; 0066 0067 State state() const; 0068 bool isRunning() const; 0069 bool isFinished() const; 0070 0071 void setEmitSignals(bool emitThem); 0072 0073 /** 0074 * Sets the priority for this dynamic thread. 0075 * Can be set anytime. If the thread is currently not running, 0076 * the priority will be set when it is run next time. 0077 * When you set QThread::InheritPriority (default), the 0078 * priority is not changed but inherited from the thread pool. 0079 */ 0080 void setPriority(QThread::Priority priority); 0081 QThread::Priority priority() const; 0082 0083 public Q_SLOTS: 0084 0085 void start(); 0086 0087 /** 0088 * Stop computation, sets the running flag to false. 0089 */ 0090 void stop(); 0091 0092 /** 0093 * Waits until the thread finishes. Typically, call stop() before. 0094 */ 0095 void wait(); 0096 0097 Q_SIGNALS: 0098 0099 /** 0100 * Emitted if emitSignals is enabled 0101 */ 0102 void starting(); 0103 void finished(); 0104 0105 protected: 0106 0107 /** 0108 * If you are deleting data in your destructor which is accessed from the thread, 0109 * do one of the following from your destructor to guarantee a safe shutdown: 0110 * 1) Call this method 0111 * 2) Call stop() and wait(), knowing that nothing will 0112 * call start() anymore after this 0113 * 3) Be sure the thread will never be running at destruction. 0114 * Note: This irrevocably stops this object. 0115 * Note: It is not sufficient that your parent class does this. 0116 * Calling this method, or providing one of the above mentioned 0117 * equivalent guarantees, must be done by every 0118 * single last class in the hierarchy with an implemented destructor deleting data. 0119 * (the base class destructor is always called after the derived class) 0120 */ 0121 void shutDown(); 0122 0123 /** 0124 * In you run() method, you shall regularly check for runningFlag() 0125 * and cleanup and return if false. 0126 */ 0127 bool runningFlag() const volatile; 0128 0129 /** 0130 * This is the non-recursive mutex used to protect state variables 0131 * and waiting in this class. You can use it if you want to protect 0132 * your memory in the same scope as calling start, stop or wait, 0133 * then using the QMutexLocker variants below. Note that when you have locked this mutex, 0134 * you must use these variants, as the mutex is non-recursive. 0135 */ 0136 QMutex* threadMutex() const; 0137 0138 /** 0139 * Doing the same as start(), stop() and wait above, provide it 0140 * with a locked QMutexLocker on mutex(). 0141 * Note the start() will unlock and relock for scheduling once, after state change. 0142 */ 0143 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0144 0145 void start(QMutexLocker<QMutex>& locker); 0146 void stop(QMutexLocker<QMutex>& locker); 0147 void wait(QMutexLocker<QMutex>& locker); 0148 0149 #else 0150 0151 void start(QMutexLocker& locker); 0152 void stop(QMutexLocker& locker); 0153 void wait(QMutexLocker& locker); 0154 0155 #endif 0156 0157 private: 0158 0159 // Disable 0160 DynamicThread(const DynamicThread&) = delete; 0161 DynamicThread& operator=(const DynamicThread&) = delete; 0162 0163 private: 0164 0165 friend class DynamicThreadPriv; 0166 0167 class Private; 0168 Private* const d; 0169 }; 0170 0171 } // namespace Digikam 0172 0173 #endif // DIGIKAM_DYNAMIC_THREAD_H