T66 A new smart pointer for managing a CContinuousWorker subclass instance.

Owns the worker before it starts, when ownership is transferred to the thread.
This commit is contained in:
Mathew Sutcliffe
2017-05-06 23:46:53 +01:00
parent ca81c65eae
commit 41ff563e19
4 changed files with 70 additions and 8 deletions

View File

@@ -56,6 +56,7 @@ namespace BlackMisc
CWorker *CWorker::fromTaskImpl(QObject *owner, const QString &name, int typeId, std::function<CVariant()> 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);

View File

@@ -23,6 +23,7 @@
#include <QMutex>
#include <QMutexLocker>
#include <QObject>
#include <QPointer>
#include <QSharedPointer>
#include <QString>
#include <QThread>
@@ -31,12 +32,16 @@
#include <QtGlobal>
#include <algorithm>
#include <functional>
#include <memory>
#include <type_traits>
#include <atomic>
namespace BlackMisc
{
template <typename T>
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 <typename T>
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 <typename T>
class CWorkerPointer
{
public:
static_assert(std::is_base_of<CContinuousWorker, T>::value, "T must be a CContinuousWorker subclass");
//! Constructor. Takes ownership.
explicit CWorkerPointer(T *ptr) : m_weak(ptr)
{
if (!ptr || static_cast<const CContinuousWorker *>(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 <typename... Ts>
static CWorkerPointer create(Ts &&... args) { return CWorkerPointer(new T(std::forward<Ts>(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<T> m_strong;
QPointer<T> m_weak;
};
}
#endif