Fix task cancelling
This commit is contained in:
parent
8091183375
commit
104ecb528a
1 changed files with 79 additions and 31 deletions
|
|
@ -50,24 +50,22 @@ namespace psemek::async
|
|||
using type = util::function<void()>;
|
||||
};
|
||||
|
||||
struct cancel_token
|
||||
{};
|
||||
|
||||
template <typename T>
|
||||
struct task_state
|
||||
{
|
||||
std::atomic<bool> canceled = false;
|
||||
bool const auto_cancel;
|
||||
|
||||
std::mutex value_mutex;
|
||||
typename task_value_container<T>::type value{};
|
||||
std::exception_ptr exception;
|
||||
|
||||
std::condition_variable value_cv;
|
||||
|
||||
std::shared_ptr<cancel_token> shared_cancel;
|
||||
std::weak_ptr<cancel_token> weak_cancel;
|
||||
|
||||
std::mutex then_mutex;
|
||||
typename then_function<T>::type then_func;
|
||||
|
||||
task_state(bool auto_cancel)
|
||||
: auto_cancel{auto_cancel}
|
||||
{}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -95,8 +93,9 @@ namespace psemek::async
|
|||
future() = default;
|
||||
future(future&&) = default;
|
||||
|
||||
future(std::shared_ptr<detail::task_state<T>> state)
|
||||
future(std::shared_ptr<detail::task_state<T>> state, std::shared_ptr<detail::cancel_token> cancel)
|
||||
: state_(std::move(state))
|
||||
, cancel_(std::move(cancel))
|
||||
{}
|
||||
|
||||
future & operator = (future&&) = default;
|
||||
|
|
@ -108,10 +107,8 @@ namespace psemek::async
|
|||
|
||||
void reset()
|
||||
{
|
||||
if (state_ && state_->auto_cancel)
|
||||
cancel();
|
||||
|
||||
state_.reset();
|
||||
cancel_.reset();
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
|
|
@ -149,7 +146,7 @@ namespace psemek::async
|
|||
{
|
||||
if (!state_)
|
||||
throw empty_future_error{};
|
||||
if (state_->canceled)
|
||||
if (!state_->weak_cancel.lock())
|
||||
throw canceled_task_error{};
|
||||
wait();
|
||||
if (state_->value)
|
||||
|
|
@ -165,8 +162,9 @@ namespace psemek::async
|
|||
|
||||
void cancel()
|
||||
{
|
||||
if (state_)
|
||||
state_->canceled = true;
|
||||
if (!state_) throw empty_future_error{};
|
||||
|
||||
cancel_.reset();
|
||||
}
|
||||
|
||||
bool ready() const
|
||||
|
|
@ -179,6 +177,7 @@ namespace psemek::async
|
|||
|
||||
private:
|
||||
std::shared_ptr<detail::task_state<T>> state_;
|
||||
std::shared_ptr<detail::cancel_token> cancel_;
|
||||
|
||||
bool has_value_unsafe() const
|
||||
{
|
||||
|
|
@ -205,12 +204,26 @@ namespace psemek::async
|
|||
{}
|
||||
|
||||
promise()
|
||||
: state_{std::make_shared<detail::task_state<T>>(false)}
|
||||
{}
|
||||
: state_{std::make_shared<detail::task_state<T>>()}
|
||||
, cancel_{std::make_shared<detail::cancel_token>()}
|
||||
{
|
||||
state_->shared_cancel = cancel_;
|
||||
state_->weak_cancel = cancel_;
|
||||
}
|
||||
|
||||
promise(auto_cancel_tag tag)
|
||||
: state_{std::make_shared<detail::task_state<T>>(true)}
|
||||
{}
|
||||
promise(auto_cancel_tag)
|
||||
: state_{std::make_shared<detail::task_state<T>>()}
|
||||
, cancel_{std::make_shared<detail::cancel_token>()}
|
||||
{
|
||||
state_->weak_cancel = cancel_;
|
||||
}
|
||||
|
||||
promise(std::shared_ptr<detail::cancel_token> cancel)
|
||||
: state_{std::make_shared<detail::task_state<T>>()}
|
||||
, cancel_{cancel}
|
||||
{
|
||||
state_->weak_cancel = cancel_;
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
|
|
@ -249,13 +262,19 @@ namespace psemek::async
|
|||
state_->exception = std::move(e);
|
||||
}
|
||||
|
||||
future<T> get_future() const
|
||||
future<T> get_future()
|
||||
{
|
||||
return future<T>(state_);
|
||||
return future<T>(state_, std::move(cancel_));
|
||||
}
|
||||
|
||||
bool canceled() const
|
||||
{
|
||||
return !state_->weak_cancel.lock();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<detail::task_state<T>> state_;
|
||||
std::shared_ptr<detail::cancel_token> cancel_;
|
||||
};
|
||||
|
||||
template <>
|
||||
|
|
@ -265,12 +284,26 @@ namespace psemek::async
|
|||
{}
|
||||
|
||||
promise()
|
||||
: state_{std::make_shared<detail::task_state<void>>(false)}
|
||||
{}
|
||||
: state_{std::make_shared<detail::task_state<void>>()}
|
||||
, cancel_{std::make_shared<detail::cancel_token>()}
|
||||
{
|
||||
state_->shared_cancel = cancel_;
|
||||
state_->weak_cancel = cancel_;
|
||||
}
|
||||
|
||||
promise(auto_cancel_tag)
|
||||
: state_{std::make_shared<detail::task_state<void>>(true)}
|
||||
{}
|
||||
: state_{std::make_shared<detail::task_state<void>>()}
|
||||
, cancel_{std::make_shared<detail::cancel_token>()}
|
||||
{
|
||||
state_->weak_cancel = cancel_;
|
||||
}
|
||||
|
||||
promise(std::shared_ptr<detail::cancel_token> cancel)
|
||||
: state_{std::make_shared<detail::task_state<void>>()}
|
||||
, cancel_{cancel}
|
||||
{
|
||||
state_->weak_cancel = cancel_;
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
|
|
@ -297,13 +330,19 @@ namespace psemek::async
|
|||
state_->exception = std::move(e);
|
||||
}
|
||||
|
||||
future<void> get_future() const
|
||||
future<void> get_future()
|
||||
{
|
||||
return future<void>(state_);
|
||||
return future<void>(state_, std::move(cancel_));
|
||||
}
|
||||
|
||||
bool canceled() const
|
||||
{
|
||||
return !state_->weak_cancel.lock();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<detail::task_state<void>> state_;
|
||||
std::shared_ptr<detail::cancel_token> cancel_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -335,12 +374,18 @@ namespace psemek::async
|
|||
, func_(std::forward<F>(f))
|
||||
{}
|
||||
|
||||
template <typename F>
|
||||
packaged_task(std::shared_ptr<detail::cancel_token> cancel, F && f)
|
||||
: promise_(cancel)
|
||||
, func_(std::forward<F>(f))
|
||||
{}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return static_cast<bool>(promise_);
|
||||
}
|
||||
|
||||
future<R> get_future() const
|
||||
future<R> get_future()
|
||||
{
|
||||
return promise_.get_future();
|
||||
}
|
||||
|
|
@ -348,6 +393,9 @@ namespace psemek::async
|
|||
template <typename ... Args1>
|
||||
void operator() (Args1 && ... args)
|
||||
{
|
||||
if (promise_.canceled())
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
if constexpr (std::is_same_v<R, void>)
|
||||
|
|
@ -427,7 +475,7 @@ namespace psemek::async
|
|||
if constexpr (std::is_same_v<T, void>)
|
||||
{
|
||||
using R = decltype(f());
|
||||
packaged_task<R()> t(std::forward<F>(f));
|
||||
packaged_task<R()> t(cancel_, std::forward<F>(f));
|
||||
auto fut = t.get_future();
|
||||
|
||||
std::lock_guard lock{state_->then_mutex};
|
||||
|
|
@ -437,7 +485,7 @@ namespace psemek::async
|
|||
else
|
||||
{
|
||||
using R = decltype(f(*(state_->value)));
|
||||
packaged_task<R(T &)> t(std::forward<F>(f));
|
||||
packaged_task<R(T &)> t(cancel_, std::forward<F>(f));
|
||||
auto fut = t.get_future();
|
||||
|
||||
std::lock_guard lock{state_->then_mutex};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue