diff --git a/libs/async/include/psemek/async/future.hpp b/libs/async/include/psemek/async/future.hpp index e6863889..0945aed5 100644 --- a/libs/async/include/psemek/async/future.hpp +++ b/libs/async/include/psemek/async/future.hpp @@ -55,7 +55,8 @@ namespace psemek::async std::weak_ptr weak_cancel; std::mutex then_mutex; - typename then_function::type then_func; + std::vector::type> then_funcs; + std::vector> then_exception_funcs; }; } @@ -85,14 +86,16 @@ namespace psemek::async using result_type = T; future() = default; - future(future&&) = default; + future(future const &) = default; + future(future &&) = default; future(std::shared_ptr> state, std::shared_ptr cancel) : state_(std::move(state)) , cancel_(std::move(cancel)) {} - future & operator = (future&&) = default; + future & operator = (future const &) = default; + future & operator = (future &&) = default; ~future() { @@ -239,8 +242,10 @@ namespace psemek::async state_->value = value; } state_->value_cv.notify_all(); - if (state_->then_func) - state_->then_func(*state_->value); + + std::lock_guard lock{state_->then_mutex}; + for (auto & func : state_->then_funcs) + func(*state_->value); } void set_value(T && value) @@ -252,8 +257,10 @@ namespace psemek::async state_->value = std::move(value); } state_->value_cv.notify_all(); - if (state_->then_func) - state_->then_func(*state_->value); + + std::lock_guard lock{state_->then_mutex}; + for (auto & func : state_->then_funcs) + func(*state_->value); } void set_exception(std::exception_ptr e) @@ -263,6 +270,10 @@ namespace psemek::async std::lock_guard lock{state_->value_mutex}; if (state_->value || state_->exception) throw satisfied_promise_error{}; state_->exception = std::move(e); + + std::lock_guard lock_then{state_->then_mutex}; + for (auto & func : state_->then_exception_funcs) + func(state_->exception); } state_->value_cv.notify_all(); } @@ -324,8 +335,10 @@ namespace psemek::async state_->value = true; } state_->value_cv.notify_all(); - if (state_->then_func) - state_->then_func(); + + std::lock_guard lock{state_->then_mutex}; + for (auto & func : state_->then_funcs) + func(); } void set_exception(std::exception_ptr e) @@ -335,6 +348,10 @@ namespace psemek::async std::lock_guard lock{state_->value_mutex}; if (state_->value || state_->exception) throw satisfied_promise_error{}; state_->exception = std::move(e); + + std::lock_guard lock_then{state_->then_mutex}; + for (auto & func : state_->then_exception_funcs) + func(state_->exception); } state_->value_cv.notify_all(); } @@ -488,7 +505,7 @@ namespace psemek::async auto fut = t.get_future(); std::lock_guard lock{state_->then_mutex}; - state_->then_func = std::move(t); + state_->then_funcs.push_back(std::move(t)); return fut; } else @@ -498,7 +515,7 @@ namespace psemek::async auto fut = t.get_future(); std::lock_guard lock{state_->then_mutex}; - state_->then_func = std::move(t); + state_->then_funcs.push_back(std::move(t)); return fut; } }