Support auto-canceled tasks
This commit is contained in:
parent
5f91587a39
commit
a6b931e8e2
1 changed files with 62 additions and 4 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue