Support auto-canceled tasks

This commit is contained in:
Nikita Lisitsa 2020-11-21 15:43:42 +03:00
parent 5f91587a39
commit a6b931e8e2

View file

@ -17,6 +17,11 @@ namespace psemek::util
{
std::promise<T> promise;
std::atomic<bool> canceled = false;
bool const auto_cancel;
task_state(bool auto_cancel)
: auto_cancel{auto_cancel}
{}
};
template <typename T, typename F, typename ... Args>
@ -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 <typename T>
struct future
{
future() = default;
future(std::shared_ptr<detail::task_state<T>> 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<T>();
}
explicit operator bool() const
{
return static_cast<bool>(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 <typename F, typename ... Args>
auto dispatch(F && f, Args && ... args);
// Post a callable for execution. Retuns a future.
// The task cancels on future destruction.
template <typename F, typename ... Args>
auto dispatch(auto_cancel_tag, F && f, Args && ... args);
// Post a callable for execution at a certain time point.
// Retuns a future.
template <typename TimePoint, typename F, typename ... Args>
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 <typename TimePoint, typename F, typename ... Args>
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<detail::task_state<R>>();
auto state = std::make_shared<detail::task_state<R>>(false);
post(detail::wrap_task(state, std::forward<F>(f), std::forward<Args>(args)...));
return future<R>(state);
}
template <typename F, typename ... Args>
auto executor::dispatch(auto_cancel_tag, F && f, Args && ... args)
{
using R = decltype(f());
auto state = std::make_shared<detail::task_state<R>>(true);
post(detail::wrap_task(state, std::forward<F>(f), std::forward<Args>(args)...));
return future<R>(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<detail::task_state<R>>();
auto state = std::make_shared<detail::task_state<R>>(false);
post_at(std::chrono::time_point_cast<clock::duration>(time), detail::wrap_task(state, std::forward<F>(f), std::forward<Args>(args)...));
return future<R>(state);
}
template <typename TimePoint, typename F, typename ... Args>
auto executor::dispatch_at(TimePoint time, auto_cancel_tag, F && f, Args && ... args)
{
using R = decltype(f());
auto state = std::make_shared<detail::task_state<R>>(true);
post_at(std::chrono::time_point_cast<clock::duration>(time), detail::wrap_task(state, std::forward<F>(f), std::forward<Args>(args)...));
return future<R>(state);
}