From 38afbed3704c5d21db26758d9ce78078710abaa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Sat, 7 Feb 2015 17:51:41 +0100 Subject: Async: don't leak Executors We now hold executors in shared pointers. We cannot easilly delete them, as they are referenced from two objects (the Job they belong to, and the next job), and the lifetime of the jobs is unclear. --- async/src/async.cpp | 4 ++-- async/src/async.h | 58 ++++++++++++++++++++++++++--------------------------- 2 files changed, 30 insertions(+), 32 deletions(-) (limited to 'async') diff --git a/async/src/async.cpp b/async/src/async.cpp index 921a6b5..c9fedc7 100644 --- a/async/src/async.cpp +++ b/async/src/async.cpp @@ -24,7 +24,7 @@ using namespace Async; -Private::ExecutorBase::ExecutorBase(ExecutorBase* parent) +Private::ExecutorBase::ExecutorBase(const ExecutorBasePtr &parent) : mPrev(parent) , mResult(0) { @@ -36,7 +36,7 @@ Private::ExecutorBase::~ExecutorBase() } -JobBase::JobBase(Private::ExecutorBase *executor) +JobBase::JobBase(const Private::ExecutorBasePtr &executor) : mExecutor(executor) { } diff --git a/async/src/async.h b/async/src/async.h index 753a44f..d15373b 100644 --- a/async/src/async.h +++ b/async/src/async.h @@ -29,10 +29,12 @@ #include #include +#include /* - * TODO: on .then and potentially others: support for ThenTask without future argument and return value which makes it implicitly a sync continuation. Useful for typical value consumer continuations. + * TODO: on .then and potentially others: support for ThenTask without future argument and return value which makes it implicitly a sync continuation. + * Useful for typical value consumer continuations. * TODO: error continuation on .then and others. * TODO: instead of passing the future objects callbacks could be provided for result reporting (we can still use the future object internally */ @@ -57,6 +59,10 @@ using ErrorHandler = std::function; namespace Private { +class ExecutorBase; +typedef QSharedPointer ExecutorBasePtr; + + template struct PreviousOut { using type = typename std::tuple_element<0, std::tuple>::type; @@ -77,9 +83,9 @@ public: } protected: - ExecutorBase(ExecutorBase *parent); + ExecutorBase(const ExecutorBasePtr &parent); - ExecutorBase *mPrev; + ExecutorBasePtr mPrev; FutureBase *mResult; }; @@ -87,7 +93,7 @@ template class Executor : public ExecutorBase { protected: - Executor(ExecutorBase *parent) + Executor(const Private::ExecutorBasePtr &parent) : ExecutorBase(parent) , mPrevFuture(0) {} @@ -106,7 +112,7 @@ template class ThenExecutor: public Executor::type, Out, In ...> { public: - ThenExecutor(ThenTask then, ErrorHandler errorHandler = ErrorHandler(), ExecutorBase *parent = nullptr); + ThenExecutor(ThenTask then, ErrorHandler errorHandler = ErrorHandler(), const ExecutorBasePtr &parent = ExecutorBasePtr()); void previousFutureReady(); }; @@ -114,7 +120,7 @@ template class EachExecutor : public Executor { public: - EachExecutor(EachTask each, ExecutorBase *parent); + EachExecutor(EachTask each, const ExecutorBasePtr &parent); void previousFutureReady(); private: @@ -122,11 +128,10 @@ private: }; template -class ReduceExecutor : public Executor +class ReduceExecutor : public ThenExecutor { public: - ReduceExecutor(ReduceTask reduce, ExecutorBase *parent); - void previousFutureReady(); + ReduceExecutor(ReduceTask reduce, const ExecutorBasePtr &parent); }; } // namespace Private @@ -175,11 +180,11 @@ class JobBase friend class Job; public: - JobBase(Private::ExecutorBase *executor); + JobBase(const Private::ExecutorBasePtr &executor); ~JobBase(); protected: - Private::ExecutorBase *mExecutor; + Private::ExecutorBasePtr mExecutor; }; /** @@ -237,9 +242,8 @@ public: template Job then(ThenTask func, ErrorHandler errorFunc = ErrorHandler()) { - //FIXME are we leaking the executor? - //The executor is copied with ever job instance, so use a sharedpointer? - return Job(new Private::ThenExecutor(func, errorFunc, mExecutor)); + return Job(Private::ExecutorBasePtr( + new Private::ThenExecutor(func, errorFunc, mExecutor))); } template @@ -249,7 +253,8 @@ public: "The 'Each' task can only be connected to a job that returns a list or an array."); static_assert(detail::isIterable::value, "The result type of 'Each' task must be a list or an array."); - return Job(new Private::EachExecutor(func, mExecutor)); + return Job(Private::ExecutorBasePtr( + new Private::EachExecutor(func, mExecutor))); } template @@ -259,7 +264,8 @@ public: "The 'Result' task can only be connected to a job that returns a list or an array"); static_assert(std::is_same::value, "The return type of previous task must be compatible with input type of this task"); - return Job(new Private::ReduceExecutor(func, mExecutor)); + return Job(Private::ExecutorBasePtr( + new Private::ReduceExecutor(func, mExecutor))); } Async::Future exec() @@ -274,7 +280,7 @@ public: } private: - Job(Private::ExecutorBase *executor) + Job(Private::ExecutorBasePtr executor) : JobBase(executor) {} }; @@ -289,8 +295,7 @@ namespace Async { template Job start(ThenTask func) { - //FIXME we're leaking the exucutor, use a shared pointer - return Job(new Private::ThenExecutor(func)); + return Job(Private::ExecutorBasePtr(new Private::ThenExecutor(func))); } namespace Private { @@ -326,7 +331,7 @@ void Executor::exec() } template -ThenExecutor::ThenExecutor(ThenTask then, ErrorHandler error, ExecutorBase* parent) +ThenExecutor::ThenExecutor(ThenTask then, ErrorHandler error, const ExecutorBasePtr &parent) : Executor::type, Out, In ...>(parent) { this->mFunc = then; @@ -356,7 +361,7 @@ void ThenExecutor::previousFutureReady() } template -EachExecutor::EachExecutor(EachTask each, ExecutorBase* parent) +EachExecutor::EachExecutor(EachTask each, const ExecutorBasePtr &parent) : Executor(parent) { this->mFunc = each; @@ -393,18 +398,11 @@ void EachExecutor::previousFutureReady() } template -ReduceExecutor::ReduceExecutor(ReduceTask reduce, ExecutorBase* parent) - : Executor(parent) +ReduceExecutor::ReduceExecutor(ReduceTask reduce, const ExecutorBasePtr &parent) + : ThenExecutor(reduce, ErrorHandler(), parent) { - this->mFunc = reduce; } -template -void ReduceExecutor::previousFutureReady() -{ - assert(this->mPrevFuture->isFinished()); - this->mFunc(this->mPrevFuture->value(), *static_cast*>(this->mResult)); -} } // namespace Private -- cgit v1.2.3