File indexing completed on 2025-03-09 03:56:12
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2010-04-06 0007 * Description : Multithreaded worker object 0008 * 0009 * SPDX-FileCopyrightText: 2010-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #ifndef DIGIKAM_WORKER_OBJECT_H 0017 #define DIGIKAM_WORKER_OBJECT_H 0018 0019 // Qt includes 0020 0021 #include <QObject> 0022 #include <QThread> 0023 0024 // Local includes 0025 0026 #include "digikam_export.h" 0027 0028 class QEventLoop; 0029 0030 namespace Digikam 0031 { 0032 0033 class WorkerObjectRunnable; 0034 0035 class DIGIKAM_EXPORT WorkerObject : public QObject 0036 { 0037 Q_OBJECT 0038 0039 public: 0040 0041 enum State 0042 { 0043 Inactive, 0044 Scheduled, 0045 Running, 0046 Deactivating 0047 }; 0048 0049 enum DeactivatingMode 0050 { 0051 FlushSignals, ///< Already sent signals are cleared 0052 KeepSignals, ///< The thread is stopped, but already sent signals remain in the queue 0053 PhaseOut ///< The thread is stopped when all signals emitted until now have been processed 0054 }; 0055 0056 public: 0057 0058 /** 0059 * Deriving from a worker object allows you to execute your slots in a thread. 0060 * Implement any slots and connect signals just as usual. 0061 * Call schedule() before or when signals are emitted. The object 0062 * will have moved to a thread when the signals are received by the slots. 0063 * Call deactivate() to stop computation. 0064 * Note that without calling schedule(), no signal will ever be processed. 0065 * You can use the connectAndSchedule convenience connection to avoid 0066 * having to call schedule() directly. 0067 * Note that you cannot make this QObject the child of another QObject. 0068 * Please check if you need to call shutDown from your destructor (see below). 0069 */ 0070 explicit WorkerObject(); 0071 ~WorkerObject() override; 0072 0073 State state() const; 0074 0075 void wait(); 0076 0077 /** 0078 * Sets the priority for this dynamic thread. 0079 * Can be set anytime. If the thread is currently not running, 0080 * the priority will be set when it is run next time. 0081 * When you set QThread::InheritPriority (default), the 0082 * priority is not changed but inherited from the thread pool. 0083 */ 0084 void setPriority(QThread::Priority priority); 0085 QThread::Priority priority() const; 0086 0087 /** 0088 * You must normally call schedule() to ensure that the object is active when you send 0089 * a signal with work data. Instead, you can use these connect() methods 0090 * when connecting your signal to this object, the signal that carries work data. 0091 * Then the object will be scheduled each time you emit the signal. 0092 */ 0093 bool connectAndSchedule(const QObject* sender, 0094 const char* signal, 0095 const char* method, 0096 Qt::ConnectionType type = Qt::AutoConnection) const; 0097 0098 static bool connectAndSchedule(const QObject* sender, 0099 const char* signal, 0100 const WorkerObject* receiver, 0101 const char* method, 0102 Qt::ConnectionType type = Qt::AutoConnection); 0103 0104 static bool disconnectAndSchedule(const QObject* sender, 0105 const char* signal, 0106 const WorkerObject* receiver, 0107 const char* method); 0108 0109 public Q_SLOTS: 0110 0111 /** 0112 * Starts execution of this worker object: 0113 * The object is moved to a thread and an event loop started, 0114 * so that queued signals will be received. 0115 */ 0116 void schedule(); 0117 0118 /** 0119 * Quits execution of this worker object. 0120 * If mode is FlushSignals, all already emitted signals will be cleared. 0121 * If mode is KeepSignals, already emitted signals are not cleared and 0122 * will be kept in the event queue until destruction or schedule() is called. 0123 * If mode is PhaseOut, already emitted signals will be processed 0124 * and the thread quit immediately afterwards. 0125 */ 0126 void deactivate(DeactivatingMode mode = FlushSignals); 0127 0128 Q_SIGNALS: 0129 0130 void started(); 0131 void finished(); 0132 0133 protected: 0134 0135 bool transitionToRunning(); 0136 void transitionToInactive(); 0137 0138 void run(); 0139 void setEventLoop(QEventLoop* loop); 0140 void addRunnable(WorkerObjectRunnable* loop); 0141 void removeRunnable(WorkerObjectRunnable* loop); 0142 0143 /** 0144 * If you are deleting data in your destructor which is accessed from the thread, 0145 * do one of the following from your destructor to guarantee a safe shutdown: 0146 * 1) Call this method 0147 * 2) Call stop() and wait(), knowing that nothing will 0148 * call start() anymore after this 0149 * 3) Be sure the thread will never be running at destruction. 0150 * Note: This irrevocably stops this object. 0151 * Note: It is not sufficient that your parent class does this. 0152 * Calling this method, or providing one of the above mentioned 0153 * equivalent guarantees, must be done by every 0154 * single last class in the hierarchy with an implemented destructor deleting data. 0155 * (the base class destructor is always called after the derived class) 0156 */ 0157 void shutDown(); 0158 0159 /** 0160 * Called from within thread's event loop to quit processing. 0161 * Quit any blocking operation. 0162 * Immediately afterwards, the event loop will be quit. 0163 */ 0164 virtual void aboutToQuitLoop(); 0165 0166 /** 0167 * Called from deactivate(), typically from a different 0168 * thread than the worker thread, possibly the UI thread. 0169 * You can stop any extra controlled threads here. 0170 * Immediately afterwards, an event will be sent to the working 0171 * thread which will cause the event loop to quit. (aboutToQuitLoop()) 0172 */ 0173 virtual void aboutToDeactivate(); 0174 0175 bool event(QEvent* e) override; 0176 0177 private: 0178 0179 friend class WorkerObjectRunnable; 0180 friend class ThreadManager; 0181 0182 private: 0183 0184 // Disable. 0185 WorkerObject(const WorkerObject&) = delete; 0186 WorkerObject& operator=(const WorkerObject&) = delete; 0187 WorkerObject(QObject*) = delete; 0188 0189 private: 0190 0191 class Private; 0192 Private* const d; 0193 }; 0194 0195 } // namespace Digikam 0196 0197 #endif // DIGIKAM_WORKER_OBJECT_H