diff --git a/src/blackmisc/worker.cpp b/src/blackmisc/worker.cpp index 13484882c..661314254 100644 --- a/src/blackmisc/worker.cpp +++ b/src/blackmisc/worker.cpp @@ -56,6 +56,7 @@ namespace BlackMisc CWorker *CWorker::fromTaskImpl(QObject *owner, const QString &name, int typeId, std::function task) { auto *worker = new CWorker(task); + emit worker->aboutToStart(); worker->setStarted(); auto *thread = new CRegularThread(owner); @@ -122,6 +123,7 @@ namespace BlackMisc if (m_name.isEmpty()) { m_name = metaObject()->className(); } + emit aboutToStart(); setStarted(); auto *thread = new CRegularThread(m_owner); diff --git a/src/blackmisc/worker.h b/src/blackmisc/worker.h index 9de5d58c3..adf1d7e6d 100644 --- a/src/blackmisc/worker.h +++ b/src/blackmisc/worker.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -31,12 +32,16 @@ #include #include #include +#include #include #include namespace BlackMisc { + template + class CWorkerPointer; + /*! * Starts a single-shot timer which will call a task in the thread of the given object when it times out. * @@ -158,6 +163,9 @@ namespace BlackMisc void abandonAndWait() noexcept; signals: + //! Emitted when the task is about to start. + void aboutToStart(); + //! Emitted when the task is finished. void finished(); @@ -292,6 +300,9 @@ namespace BlackMisc void ps_finish(); private: + template + friend class CWorkerPointer; + using CWorkerBase::hasStarted; using CWorkerBase::setStarted; using CWorkerBase::setFinished; @@ -300,6 +311,59 @@ namespace BlackMisc QString m_name; }; + /*! + * RAII smart pointer to manage a CContinuousWorker instance. + * + * Not required if the worker is immediately started after construction. + * Before the worker starts, it is owned by the pointer. + * After the worker starts, becomes a non-owning pointer, as ownership is tied to the lifetime of the thread. + */ + template + class CWorkerPointer + { + public: + static_assert(std::is_base_of::value, "T must be a CContinuousWorker subclass"); + + //! Constructor. Takes ownership. + explicit CWorkerPointer(T *ptr) : m_weak(ptr) + { + if (!ptr || static_cast(ptr)->hasStarted()) { return; } + m_strong.reset(ptr); + QObject::connect(ptr, &CWorkerBase::aboutToStart, [this] { m_strong.reset(); }); + } + + //! Construct a null pointer. + //! @{ + CWorkerPointer() = default; + CWorkerPointer(std::nullptr_t) {} + //! @} + + //! Factory method. + //! Arguments are forwarded to the constructor of T. Strictly more exception-safe than calling the constructor with new. + template + static CWorkerPointer create(Ts &&... args) { return CWorkerPointer(new T(std::forward(args)...)); } + + //! Access the raw pointer. + //! @{ + T *data() const { return m_weak.data(); } + T &operator *() const { return *data(); } + T *operator ->() const { return &*data(); } + //! @} + + //! True if it points to a valid worker. + //! @{ + explicit operator bool() const { return m_weak; } + bool isValid() const { return m_weak; } + //! @} + + //! True if it owns the worker it points to (i.e. worker has not yet started). + bool isOwner() const { return m_strong; } + + private: + std::unique_ptr m_strong; + QPointer m_weak; + }; + } #endif diff --git a/src/swiftdata/swiftdata.cpp b/src/swiftdata/swiftdata.cpp index 42f35ac18..801ebd156 100644 --- a/src/swiftdata/swiftdata.cpp +++ b/src/swiftdata/swiftdata.cpp @@ -8,7 +8,6 @@ */ #include "swiftdata.h" -#include "blackcore/db/backgrounddataupdater.h" #include "blackcore/data/globalsetup.h" #include "blackgui/components/datamaininfoareacomponent.h" #include "blackgui/components/dbmappingcomponent.h" @@ -163,14 +162,14 @@ void CSwiftData::consolidationSettingChanged() { ui->comp_MainInfoArea->getDataSettingsComponent()->setBackgroundUpdater(nullptr); m_updater->gracefulShutdown(); - m_updater.reset(nullptr); + m_updater = nullptr; } } else { if (!m_updater) { - m_updater.reset(new CBackgroundDataUpdater(this)); + m_updater = m_updater.create(this); m_updater->start(QThread::LowestPriority); ui->comp_MainInfoArea->getDataSettingsComponent()->setBackgroundUpdater(m_updater.data()); } diff --git a/src/swiftdata/swiftdata.h b/src/swiftdata/swiftdata.h index 35bdc5d76..3f149eed0 100644 --- a/src/swiftdata/swiftdata.h +++ b/src/swiftdata/swiftdata.h @@ -15,6 +15,7 @@ #include "blackgui/settings/guisettings.h" #include "blackgui/mainwindowaccess.h" #include "blackgui/managedstatusbar.h" +#include "blackcore/db/backgrounddataupdater.h" #include "blackmisc/identifiable.h" #include "blackmisc/statusmessage.h" @@ -28,10 +29,6 @@ namespace Ui { class CSwiftData; } namespace BlackCore { class CWebDataServices; - namespace Db - { - class CBackgroundDataUpdater; - } } /*! @@ -83,7 +80,7 @@ private: BlackGui::CManagedStatusBar m_statusBar; QScopedPointer ui; - QScopedPointer m_updater; + BlackMisc::CWorkerPointer m_updater; BlackMisc::CSettingReadOnly m_consolidationSettings { this, &CSwiftData::consolidationSettingChanged }; //!< consolidation time };