From a6b931e8e2c091145fce76f19227af4590223d18 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sat, 21 Nov 2020 15:43:42 +0300 Subject: [PATCH] Support auto-canceled tasks --- libs/util/include/psemek/util/executor.hpp | 66 ++++++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/libs/util/include/psemek/util/executor.hpp b/libs/util/include/psemek/util/executor.hpp index 03d07f78..46c8b3ea 100644 --- a/libs/util/include/psemek/util/executor.hpp +++ b/libs/util/include/psemek/util/executor.hpp @@ -17,6 +17,11 @@ namespace psemek::util { std::promise promise; std::atomic canceled = false; + bool const auto_cancel; + + task_state(bool auto_cancel) + : auto_cancel{auto_cancel} + {} }; template @@ -52,14 +57,38 @@ namespace psemek::util char const * what() const noexcept { return "task canceled"; } }; + struct auto_cancel_tag{}; + constexpr auto_cancel_tag auto_cancel; + template struct future { + future() = default; + future(std::shared_ptr> state) : state_(std::move(state)) , f_(state_->promise.get_future()) {} + ~future() + { + reset(); + } + + void reset() + { + if (state_ && state_->auto_cancel) + cancel(); + + state_.reset(); + f_ = std::future(); + } + + explicit operator bool() const + { + return static_cast(state_); + } + bool wait() const { f_.wait(); @@ -80,14 +109,15 @@ namespace psemek::util T get() { - if (state_->canceled) + if (state_ && state_->canceled) throw canceled_task_error{}; return f_.get(); } void cancel() { - state_->canceled = true; + if (state_) + state_->canceled = true; } bool ready() const @@ -143,11 +173,21 @@ namespace psemek::util template auto dispatch(F && f, Args && ... args); + // Post a callable for execution. Retuns a future. + // The task cancels on future destruction. + template + auto dispatch(auto_cancel_tag, F && f, Args && ... args); + // Post a callable for execution at a certain time point. // Retuns a future. template auto dispatch_at(TimePoint time, F && f, Args && ... args); + // Post a callable for execution at a certain time point. + // Retuns a future. The task cancels on future destruction. + template + auto dispatch_at(TimePoint time, auto_cancel_tag, F && f, Args && ... args); + virtual ~executor() {} }; @@ -155,7 +195,16 @@ namespace psemek::util auto executor::dispatch(F && f, Args && ... args) { using R = decltype(f()); - auto state = std::make_shared>(); + auto state = std::make_shared>(false); + post(detail::wrap_task(state, std::forward(f), std::forward(args)...)); + return future(state); + } + + template + auto executor::dispatch(auto_cancel_tag, F && f, Args && ... args) + { + using R = decltype(f()); + auto state = std::make_shared>(true); post(detail::wrap_task(state, std::forward(f), std::forward(args)...)); return future(state); } @@ -164,7 +213,16 @@ namespace psemek::util auto executor::dispatch_at(TimePoint time, F && f, Args && ... args) { using R = decltype(f()); - auto state = std::make_shared>(); + auto state = std::make_shared>(false); + post_at(std::chrono::time_point_cast(time), detail::wrap_task(state, std::forward(f), std::forward(args)...)); + return future(state); + } + + template + auto executor::dispatch_at(TimePoint time, auto_cancel_tag, F && f, Args && ... args) + { + using R = decltype(f()); + auto state = std::make_shared>(true); post_at(std::chrono::time_point_cast(time), detail::wrap_task(state, std::forward(f), std::forward(args)...)); return future(state); }