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