#include "src/channel.h" | #include "src/channel.h" | ||||
#include "src/scheduler.h" | #include "src/scheduler.h" | ||||
#include "src/sleep.h" | #include "src/sleep.h" | ||||
#include "src/when.h" |
} | } | ||||
template<class _Ty2> | template<class _Ty2> | ||||
awaitable_t<bool> write(_Ty2&& val) const | |||||
future_t<bool> write(_Ty2&& val) const | |||||
{ | { | ||||
awaitable_t<bool> awaitable; | |||||
promise_t<bool> awaitable; | |||||
auto awaker = std::make_shared<channel_write_awaker>( | auto awaker = std::make_shared<channel_write_awaker>( | ||||
[st = awaitable._state](channel_impl_type * chan) -> bool | [st = awaitable._state](channel_impl_type * chan) -> bool | ||||
{ | |||||
st->set_value(chan ? true : false); | |||||
return true; | |||||
}); | |||||
{ | |||||
st->set_value(chan ? true : false); | |||||
return true; | |||||
}); | |||||
_chan->write_(std::move(awaker), std::forward<_Ty2>(val)); | _chan->write_(std::move(awaker), std::forward<_Ty2>(val)); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
awaitable_t<_Ty> read() const | |||||
future_t<_Ty> read() const | |||||
{ | { | ||||
awaitable_t<_Ty> awaitable; | |||||
promise_t<_Ty> awaitable; | |||||
auto awaker = std::make_shared<channel_read_awaker>( | auto awaker = std::make_shared<channel_read_awaker>( | ||||
[st = awaitable._state](channel_impl_type *, _Ty * val, error_code fe) -> bool | [st = awaitable._state](channel_impl_type *, _Ty * val, error_code fe) -> bool | ||||
{ | |||||
if(val) | |||||
st->set_value(std::move(*val)); | |||||
else | |||||
st->throw_exception(channel_exception{ fe }); | |||||
{ | |||||
if(val) | |||||
st->set_value(std::move(*val)); | |||||
else | |||||
st->throw_exception(channel_exception{ fe }); | |||||
return true; | |||||
}); | |||||
return true; | |||||
}); | |||||
_chan->read_(std::move(awaker)); | _chan->read_(std::move(awaker)); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
template<class _Ty2> | template<class _Ty2> | ||||
awaitable_t<bool> operator << (_Ty2&& val) const | |||||
future_t<bool> operator << (_Ty2&& val) const | |||||
{ | { | ||||
return std::move(write(std::forward<_Ty2>(val))); | return std::move(write(std::forward<_Ty2>(val))); | ||||
} | } | ||||
awaitable_t<_Ty> operator co_await () const | |||||
future_t<_Ty> operator co_await () const | |||||
{ | { | ||||
return read(); | return read(); | ||||
} | } |
{ | { | ||||
} | } | ||||
awaitable_t<bool> event_t::wait() const | |||||
future_t<bool> event_t::wait() const | |||||
{ | { | ||||
awaitable_t<bool> awaitable; | |||||
promise_t<bool> awaitable; | |||||
auto awaker = std::make_shared<detail::event_awaker>( | auto awaker = std::make_shared<detail::event_awaker>( | ||||
[st = awaitable._state](detail::event_impl * e) -> bool | [st = awaitable._state](detail::event_impl * e) -> bool | ||||
}); | }); | ||||
_event->wait_(awaker); | _event->wait_(awaker); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
awaitable_t<bool> event_t::wait_until_(const clock_type::time_point & tp) const | |||||
future_t<bool> event_t::wait_until_(const clock_type::time_point & tp) const | |||||
{ | { | ||||
awaitable_t<bool> awaitable; | |||||
promise_t<bool> awaitable; | |||||
auto awaker = std::make_shared<detail::event_awaker>( | auto awaker = std::make_shared<detail::event_awaker>( | ||||
[st = awaitable._state](detail::event_impl * e) -> bool | [st = awaitable._state](detail::event_impl * e) -> bool | ||||
awaker->awake(nullptr, 1); | awaker->awake(nullptr, 1); | ||||
}); | }); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
struct wait_any_awaker | struct wait_any_awaker | ||||
} | } | ||||
}; | }; | ||||
awaitable_t<intptr_t> event_t::wait_any_(std::vector<event_impl_ptr> && evts) | |||||
future_t<intptr_t> event_t::wait_any_(std::vector<event_impl_ptr> && evts) | |||||
{ | { | ||||
awaitable_t<intptr_t> awaitable; | |||||
promise_t<intptr_t> awaitable; | |||||
if (evts.size() <= 0) | if (evts.size() <= 0) | ||||
{ | { | ||||
awaitable._state->set_value(-1); | awaitable._state->set_value(-1); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
auto awaker = std::make_shared<detail::event_awaker>( | auto awaker = std::make_shared<detail::event_awaker>( | ||||
e->wait_(awaker); | e->wait_(awaker); | ||||
} | } | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
awaitable_t<intptr_t> event_t::wait_any_until_(const clock_type::time_point & tp, std::vector<event_impl_ptr> && evts) | |||||
future_t<intptr_t> event_t::wait_any_until_(const clock_type::time_point & tp, std::vector<event_impl_ptr> && evts) | |||||
{ | { | ||||
awaitable_t<intptr_t> awaitable; | |||||
promise_t<intptr_t> awaitable; | |||||
auto awaker = std::make_shared<detail::event_awaker>( | auto awaker = std::make_shared<detail::event_awaker>( | ||||
[st = awaitable._state, evts](detail::event_impl * e) -> bool | [st = awaitable._state, evts](detail::event_impl * e) -> bool | ||||
awaker->awake(nullptr, 1); | awaker->awake(nullptr, 1); | ||||
}); | }); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
awaitable_t<bool> event_t::wait_all_(std::vector<event_impl_ptr> && evts) | |||||
future_t<bool> event_t::wait_all_(std::vector<event_impl_ptr> && evts) | |||||
{ | { | ||||
awaitable_t<bool> awaitable; | |||||
promise_t<bool> awaitable; | |||||
if (evts.size() <= 0) | if (evts.size() <= 0) | ||||
{ | { | ||||
awaitable._state->set_value(false); | awaitable._state->set_value(false); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
auto awaker = std::make_shared<detail::event_awaker>( | auto awaker = std::make_shared<detail::event_awaker>( | ||||
e->wait_(awaker); | e->wait_(awaker); | ||||
} | } | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
//超时后的行为应该表现为: | //超时后的行为应该表现为: | ||||
//要么所有的事件计数减一,要么所有事件计数不动 | //要么所有的事件计数减一,要么所有事件计数不动 | ||||
//则需要超时后,恢复已经等待的事件计数 | //则需要超时后,恢复已经等待的事件计数 | ||||
awaitable_t<bool> event_t::wait_all_until_(const clock_type::time_point & tp, std::vector<event_impl_ptr> && evts) | |||||
future_t<bool> event_t::wait_all_until_(const clock_type::time_point & tp, std::vector<event_impl_ptr> && evts) | |||||
{ | { | ||||
awaitable_t<bool> awaitable; | |||||
promise_t<bool> awaitable; | |||||
if (evts.size() <= 0) | if (evts.size() <= 0) | ||||
{ | { | ||||
this_scheduler()->timer()->add_handler(tp, | this_scheduler()->timer()->add_handler(tp, | ||||
{ | { | ||||
st->set_value(false); | st->set_value(false); | ||||
}); | }); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
auto ctx = std::make_shared<wait_all_ctx>(); | auto ctx = std::make_shared<wait_all_ctx>(); | ||||
} | } | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
} | } |
RF_API awaitable_t<bool> | |||||
RF_API future_t<bool> | |||||
wait() const; | wait() const; | ||||
template<class _Rep, class _Period> | template<class _Rep, class _Period> | ||||
awaitable_t<bool> | |||||
future_t<bool> | |||||
wait_for(const std::chrono::duration<_Rep, _Period> & dt) const | wait_for(const std::chrono::duration<_Rep, _Period> & dt) const | ||||
{ | { | ||||
return wait_for_(std::chrono::duration_cast<clock_type::duration>(dt)); | return wait_for_(std::chrono::duration_cast<clock_type::duration>(dt)); | ||||
} | } | ||||
template<class _Clock, class _Duration> | template<class _Clock, class _Duration> | ||||
awaitable_t<bool> | |||||
future_t<bool> | |||||
wait_until(const std::chrono::time_point<_Clock, _Duration> & tp) const | wait_until(const std::chrono::time_point<_Clock, _Duration> & tp) const | ||||
{ | { | ||||
return wait_until_(std::chrono::time_point_cast<clock_type::duration>(tp)); | return wait_until_(std::chrono::time_point_cast<clock_type::duration>(tp)); | ||||
template<class _Iter> | template<class _Iter> | ||||
static awaitable_t<intptr_t> | |||||
static future_t<intptr_t> | |||||
wait_any(_Iter begin_, _Iter end_) | wait_any(_Iter begin_, _Iter end_) | ||||
{ | { | ||||
return wait_any_(make_event_vector(begin_, end_)); | return wait_any_(make_event_vector(begin_, end_)); | ||||
} | } | ||||
template<class _Cont> | template<class _Cont> | ||||
static awaitable_t<intptr_t> | |||||
static future_t<intptr_t> | |||||
wait_any(const _Cont & cnt_) | wait_any(const _Cont & cnt_) | ||||
{ | { | ||||
return wait_any_(make_event_vector(std::begin(cnt_), std::end(cnt_))); | return wait_any_(make_event_vector(std::begin(cnt_), std::end(cnt_))); | ||||
} | } | ||||
template<class _Rep, class _Period, class _Iter> | template<class _Rep, class _Period, class _Iter> | ||||
static awaitable_t<intptr_t> | |||||
static future_t<intptr_t> | |||||
wait_any_for(const std::chrono::duration<_Rep, _Period> & dt, _Iter begin_, _Iter end_) | wait_any_for(const std::chrono::duration<_Rep, _Period> & dt, _Iter begin_, _Iter end_) | ||||
{ | { | ||||
return wait_any_for_(std::chrono::duration_cast<clock_type::duration>(dt), make_event_vector(begin_, end_)); | return wait_any_for_(std::chrono::duration_cast<clock_type::duration>(dt), make_event_vector(begin_, end_)); | ||||
} | } | ||||
template<class _Rep, class _Period, class _Cont> | template<class _Rep, class _Period, class _Cont> | ||||
static awaitable_t<intptr_t> | |||||
static future_t<intptr_t> | |||||
wait_any_for(const std::chrono::duration<_Rep, _Period> & dt, const _Cont & cnt_) | wait_any_for(const std::chrono::duration<_Rep, _Period> & dt, const _Cont & cnt_) | ||||
{ | { | ||||
return wait_any_for_(std::chrono::duration_cast<clock_type::duration>(dt), make_event_vector(std::begin(cnt_), std::end(cnt_))); | return wait_any_for_(std::chrono::duration_cast<clock_type::duration>(dt), make_event_vector(std::begin(cnt_), std::end(cnt_))); | ||||
} | } | ||||
template<class _Clock, class _Duration, class _Iter> | template<class _Clock, class _Duration, class _Iter> | ||||
static awaitable_t<intptr_t> | |||||
static future_t<intptr_t> | |||||
wait_any_until(const std::chrono::time_point<_Clock, _Duration> & tp, _Iter begin_, _Iter end_) | wait_any_until(const std::chrono::time_point<_Clock, _Duration> & tp, _Iter begin_, _Iter end_) | ||||
{ | { | ||||
return wait_any_until_(std::chrono::time_point_cast<clock_type::duration>(tp), make_event_vector(begin_, end_)); | return wait_any_until_(std::chrono::time_point_cast<clock_type::duration>(tp), make_event_vector(begin_, end_)); | ||||
} | } | ||||
template<class _Clock, class _Duration, class _Cont> | template<class _Clock, class _Duration, class _Cont> | ||||
static awaitable_t<intptr_t> | |||||
static future_t<intptr_t> | |||||
wait_any_until(const std::chrono::time_point<_Clock, _Duration> & tp, const _Cont & cnt_) | wait_any_until(const std::chrono::time_point<_Clock, _Duration> & tp, const _Cont & cnt_) | ||||
{ | { | ||||
return wait_any_until_(std::chrono::time_point_cast<clock_type::duration>(tp), make_event_vector(std::begin(cnt_), std::end(cnt_))); | return wait_any_until_(std::chrono::time_point_cast<clock_type::duration>(tp), make_event_vector(std::begin(cnt_), std::end(cnt_))); | ||||
template<class _Iter> | template<class _Iter> | ||||
static awaitable_t<bool> | |||||
static future_t<bool> | |||||
wait_all(_Iter begin_, _Iter end_) | wait_all(_Iter begin_, _Iter end_) | ||||
{ | { | ||||
return wait_all_(make_event_vector(begin_, end_)); | return wait_all_(make_event_vector(begin_, end_)); | ||||
} | } | ||||
template<class _Cont> | template<class _Cont> | ||||
static awaitable_t<bool> | |||||
static future_t<bool> | |||||
wait_all(const _Cont & cnt_) | wait_all(const _Cont & cnt_) | ||||
{ | { | ||||
return wait_all(std::begin(cnt_), std::end(cnt_)); | return wait_all(std::begin(cnt_), std::end(cnt_)); | ||||
} | } | ||||
template<class _Rep, class _Period, class _Iter> | template<class _Rep, class _Period, class _Iter> | ||||
static awaitable_t<bool> | |||||
static future_t<bool> | |||||
wait_all_for(const std::chrono::duration<_Rep, _Period> & dt, _Iter begin_, _Iter end_) | wait_all_for(const std::chrono::duration<_Rep, _Period> & dt, _Iter begin_, _Iter end_) | ||||
{ | { | ||||
return wait_all_for_(std::chrono::duration_cast<clock_type::duration>(dt), make_event_vector(begin_, end_)); | return wait_all_for_(std::chrono::duration_cast<clock_type::duration>(dt), make_event_vector(begin_, end_)); | ||||
} | } | ||||
template<class _Rep, class _Period, class _Cont> | template<class _Rep, class _Period, class _Cont> | ||||
static awaitable_t<bool> | |||||
static future_t<bool> | |||||
wait_all_for(const std::chrono::duration<_Rep, _Period> & dt, const _Cont & cnt_) | wait_all_for(const std::chrono::duration<_Rep, _Period> & dt, const _Cont & cnt_) | ||||
{ | { | ||||
return wait_all_for_(std::chrono::duration_cast<clock_type::duration>(dt), make_event_vector(std::begin(cnt_), std::end(cnt_))); | return wait_all_for_(std::chrono::duration_cast<clock_type::duration>(dt), make_event_vector(std::begin(cnt_), std::end(cnt_))); | ||||
} | } | ||||
template<class _Clock, class _Duration, class _Iter> | template<class _Clock, class _Duration, class _Iter> | ||||
static awaitable_t<bool> | |||||
static future_t<bool> | |||||
wait_all_until(const std::chrono::time_point<_Clock, _Duration> & tp, _Iter begin_, _Iter end_) | wait_all_until(const std::chrono::time_point<_Clock, _Duration> & tp, _Iter begin_, _Iter end_) | ||||
{ | { | ||||
return wait_all_until_(std::chrono::time_point_cast<clock_type::duration>(tp), make_event_vector(begin_, end_)); | return wait_all_until_(std::chrono::time_point_cast<clock_type::duration>(tp), make_event_vector(begin_, end_)); | ||||
} | } | ||||
template<class _Clock, class _Duration, class _Cont> | template<class _Clock, class _Duration, class _Cont> | ||||
static awaitable_t<bool> | |||||
static future_t<bool> | |||||
wait_all_until(const std::chrono::time_point<_Clock, _Duration> & tp, const _Cont & cnt_) | wait_all_until(const std::chrono::time_point<_Clock, _Duration> & tp, const _Cont & cnt_) | ||||
{ | { | ||||
return wait_all_until_(std::chrono::time_point_cast<clock_type::duration>(tp), make_event_vector(std::begin(cnt_), std::end(cnt_))); | return wait_all_until_(std::chrono::time_point_cast<clock_type::duration>(tp), make_event_vector(std::begin(cnt_), std::end(cnt_))); | ||||
RF_API event_t(const event_t &) = default; | RF_API event_t(const event_t &) = default; | ||||
RF_API event_t(event_t &&) = default; | RF_API event_t(event_t &&) = default; | ||||
RF_API event_t & operator = (const event_t &) = default; | RF_API event_t & operator = (const event_t &) = default; | ||||
return std::move(evts); | return std::move(evts); | ||||
} | } | ||||
inline awaitable_t<bool> wait_for_(const clock_type::duration & dt) const | |||||
public: | |||||
inline future_t<bool> wait_for_(const clock_type::duration & dt) const | |||||
{ | { | ||||
return wait_until_(clock_type::now() + dt); | return wait_until_(clock_type::now() + dt); | ||||
} | } | ||||
RF_API awaitable_t<bool> wait_until_(const clock_type::time_point & tp) const; | |||||
RF_API future_t<bool> wait_until_(const clock_type::time_point & tp) const; | |||||
RF_API static awaitable_t<intptr_t> wait_any_(std::vector<event_impl_ptr> && evts); | |||||
inline static awaitable_t<intptr_t> wait_any_for_(const clock_type::duration & dt, std::vector<event_impl_ptr> && evts) | |||||
RF_API static future_t<intptr_t> wait_any_(std::vector<event_impl_ptr> && evts); | |||||
inline static future_t<intptr_t> wait_any_for_(const clock_type::duration & dt, std::vector<event_impl_ptr> && evts) | |||||
{ | { | ||||
return wait_any_until_(clock_type::now() + dt, std::forward<std::vector<event_impl_ptr>>(evts)); | return wait_any_until_(clock_type::now() + dt, std::forward<std::vector<event_impl_ptr>>(evts)); | ||||
} | } | ||||
RF_API static awaitable_t<intptr_t> wait_any_until_(const clock_type::time_point & tp, std::vector<event_impl_ptr> && evts); | |||||
RF_API static future_t<intptr_t> wait_any_until_(const clock_type::time_point & tp, std::vector<event_impl_ptr> && evts); | |||||
RF_API static awaitable_t<bool> wait_all_(std::vector<event_impl_ptr> && evts); | |||||
inline static awaitable_t<bool> wait_all_for_(const clock_type::duration & dt, std::vector<event_impl_ptr> && evts) | |||||
RF_API static future_t<bool> wait_all_(std::vector<event_impl_ptr> && evts); | |||||
inline static future_t<bool> wait_all_for_(const clock_type::duration & dt, std::vector<event_impl_ptr> && evts) | |||||
{ | { | ||||
return wait_all_until_(clock_type::now() + dt, std::forward<std::vector<event_impl_ptr>>(evts)); | return wait_all_until_(clock_type::now() + dt, std::forward<std::vector<event_impl_ptr>>(evts)); | ||||
} | } | ||||
RF_API static awaitable_t<bool> wait_all_until_(const clock_type::time_point & tp, std::vector<event_impl_ptr> && evts); | |||||
RF_API static future_t<bool> wait_all_until_(const clock_type::time_point & tp, std::vector<event_impl_ptr> && evts); | |||||
}; | }; | ||||
} | } |
future_impl_t() = default; | future_impl_t() = default; | ||||
future_impl_t(future_impl_t&& f) = default; | future_impl_t(future_impl_t&& f) = default; | ||||
future_impl_t & operator = (future_impl_t&& f) = default; | future_impl_t & operator = (future_impl_t&& f) = default; | ||||
future_impl_t(const future_impl_t&) = delete; | |||||
future_impl_t & operator = (const future_impl_t&) = delete; | |||||
future_impl_t(const future_impl_t&) = default; | |||||
future_impl_t & operator = (const future_impl_t&) = default; | |||||
//------------------------------------------------------------------------------------------ | //------------------------------------------------------------------------------------------ | ||||
//以下是与编译器生成的resumable function交互的接口 | //以下是与编译器生成的resumable function交互的接口 | ||||
} | } | ||||
// movable, but not copyable | // movable, but not copyable | ||||
future_t(const future_t&) = delete; | |||||
future_t(const future_t&) = default; | |||||
future_t(future_t&& f) = default; | future_t(future_t&& f) = default; | ||||
future_t() = default; | future_t() = default; | ||||
future_t & operator = (const future_t&) = delete; | |||||
future_t & operator = (const future_t&) = default; | |||||
future_t & operator = (future_t&& f) = default; | future_t & operator = (future_t&& f) = default; | ||||
//------------------------------------------------------------------------------------------ | //------------------------------------------------------------------------------------------ | ||||
using promise_vt = promise_t<void>; | using promise_vt = promise_t<void>; | ||||
/* | |||||
template <typename T = void> | template <typename T = void> | ||||
struct awaitable_t | struct awaitable_t | ||||
{ | { | ||||
}; | }; | ||||
using awaitable_vt = awaitable_t<void>; | using awaitable_vt = awaitable_t<void>; | ||||
*/ | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | #if RESUMEF_ENABLE_MULT_SCHEDULER | ||||
inline promise_t<void> * state_base::parent_promise() const | inline promise_t<void> * state_base::parent_promise() const |
{ | { | ||||
} | } | ||||
awaitable_t<bool> mutex_t::lock() const | |||||
future_t<bool> mutex_t::lock() const | |||||
{ | { | ||||
awaitable_t<bool> awaitable; | |||||
promise_t<bool> awaitable; | |||||
auto awaker = std::make_shared<detail::mutex_awaker>( | auto awaker = std::make_shared<detail::mutex_awaker>( | ||||
[st = awaitable._state](detail::mutex_impl * e) -> bool | [st = awaitable._state](detail::mutex_impl * e) -> bool | ||||
}); | }); | ||||
_locker->lock_(awaker); | _locker->lock_(awaker); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
bool mutex_t::try_lock() const | bool mutex_t::try_lock() const | ||||
return _locker->try_lock_(dummy_awaker); | return _locker->try_lock_(dummy_awaker); | ||||
} | } | ||||
awaitable_t<bool> mutex_t::try_lock_until_(const clock_type::time_point & tp) const | |||||
future_t<bool> mutex_t::try_lock_until_(const clock_type::time_point & tp) const | |||||
{ | { | ||||
awaitable_t<bool> awaitable; | |||||
promise_t<bool> awaitable; | |||||
auto awaker = std::make_shared<detail::mutex_awaker>( | auto awaker = std::make_shared<detail::mutex_awaker>( | ||||
[st = awaitable._state](detail::mutex_impl * e) -> bool | [st = awaitable._state](detail::mutex_impl * e) -> bool | ||||
awaker->awake(nullptr, 1); | awaker->awake(nullptr, 1); | ||||
}); | }); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
} | } |
} | } | ||||
RF_API awaitable_t<bool> | |||||
RF_API future_t<bool> | |||||
lock() const; | lock() const; | ||||
RF_API bool | RF_API bool | ||||
try_lock() const; | try_lock() const; | ||||
RF_API mutex_t & operator = (const mutex_t &) = default; | RF_API mutex_t & operator = (const mutex_t &) = default; | ||||
RF_API mutex_t & operator = (mutex_t &&) = default; | RF_API mutex_t & operator = (mutex_t &&) = default; | ||||
private: | private: | ||||
inline awaitable_t<bool> try_lock_for_(const clock_type::duration & dt) const | |||||
inline future_t<bool> try_lock_for_(const clock_type::duration & dt) const | |||||
{ | { | ||||
return try_lock_until_(clock_type::now() + dt); | return try_lock_until_(clock_type::now() + dt); | ||||
} | } | ||||
RF_API awaitable_t<bool> try_lock_until_(const clock_type::time_point & tp) const; | |||||
RF_API future_t<bool> try_lock_until_(const clock_type::time_point & tp) const; | |||||
}; | }; | ||||
#define resumf_guard_lock(lker) (lker).lock(); resumef::scoped_lock<resumef::mutex_t> __resumf_guard##lker##__((lker), std::adopt_lock) | |||||
#define resumf_guard_lock(lker) (lker).lock(); resumef::scoped_lock<resumef::mutex_t> __resumf_guard##lker##__(std::adopt_lock, (lker)) | |||||
} | } |
namespace resumef | namespace resumef | ||||
{ | { | ||||
awaitable_t<bool> sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler & scheduler_) | |||||
future_t<bool> sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler & scheduler_) | |||||
{ | { | ||||
resumef::awaitable_t<bool> awaitable; | |||||
promise_t<bool> awaitable; | |||||
scheduler_.timer()->add(tp_, | scheduler_.timer()->add(tp_, | ||||
[st = awaitable._state](bool cancellation_requested) | [st = awaitable._state](bool cancellation_requested) | ||||
st->set_value(cancellation_requested); | st->set_value(cancellation_requested); | ||||
}); | }); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
} | } |
{ | { | ||||
struct scheduler; | struct scheduler; | ||||
RF_API awaitable_t<bool> sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler & scheduler_); | |||||
RF_API future_t<bool> sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler & scheduler_); | |||||
inline awaitable_t<bool> sleep_for_(const std::chrono::system_clock::duration& dt_, scheduler & scheduler_) | |||||
inline future_t<bool> sleep_for_(const std::chrono::system_clock::duration& dt_, scheduler & scheduler_) | |||||
{ | { | ||||
return std::move(sleep_until_(std::chrono::system_clock::now() + dt_, scheduler_)); | return std::move(sleep_until_(std::chrono::system_clock::now() + dt_, scheduler_)); | ||||
} | } | ||||
template<class _Rep, class _Period> | template<class _Rep, class _Period> | ||||
awaitable_t<bool> sleep_for(const std::chrono::duration<_Rep, _Period>& dt_, scheduler & scheduler_) | |||||
future_t<bool> sleep_for(const std::chrono::duration<_Rep, _Period>& dt_, scheduler & scheduler_) | |||||
{ | { | ||||
return std::move(sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), scheduler_)); | return std::move(sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), scheduler_)); | ||||
} | } | ||||
template<class _Rep, class _Period> | template<class _Rep, class _Period> | ||||
awaitable_t<bool> sleep_for(const std::chrono::duration<_Rep, _Period>& dt_) | |||||
future_t<bool> sleep_for(const std::chrono::duration<_Rep, _Period>& dt_) | |||||
{ | { | ||||
return std::move(sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), *this_scheduler())); | return std::move(sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), *this_scheduler())); | ||||
} | } | ||||
template<class _Clock, class _Duration = typename _Clock::duration> | template<class _Clock, class _Duration = typename _Clock::duration> | ||||
awaitable_t<bool> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_, scheduler & scheduler_) | |||||
future_t<bool> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_, scheduler & scheduler_) | |||||
{ | { | ||||
return std::move(sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), scheduler_)); | return std::move(sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), scheduler_)); | ||||
} | } | ||||
template<class _Clock, class _Duration> | template<class _Clock, class _Duration> | ||||
awaitable_t<bool> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_) | |||||
future_t<bool> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_) | |||||
{ | { | ||||
return std::move(sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), *this_scheduler())); | return std::move(sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), *this_scheduler())); | ||||
} | } |
#include "when.h" | |||||
#include <assert.h> | |||||
#include "scheduler.h" | |||||
#pragma once | |||||
#include "_awaker.h" | |||||
namespace resumef | |||||
{ | |||||
namespace detail | |||||
{ | |||||
when_impl::when_impl(intptr_t initial_counter_) | |||||
: _counter(initial_counter_) | |||||
{ | |||||
} | |||||
void when_impl::signal() | |||||
{ | |||||
scoped_lock<lock_type> lock_(this->_lock); | |||||
if (--this->_counter == 0) | |||||
{ | |||||
_awakes->awake(this, 1); | |||||
} | |||||
} | |||||
void when_impl::reset(intptr_t initial_counter_) | |||||
{ | |||||
scoped_lock<lock_type> lock_(this->_lock); | |||||
this->_awakes = nullptr; | |||||
this->_counter = initial_counter_; | |||||
} | |||||
bool when_impl::wait_(const when_awaker_ptr & awaker) | |||||
{ | |||||
assert(awaker); | |||||
scoped_lock<lock_type> lock_(this->_lock); | |||||
if (this->_counter == 0) | |||||
{ | |||||
awaker->awake(this, 1); | |||||
return true; | |||||
} | |||||
else | |||||
{ | |||||
this->_awakes = awaker; | |||||
return false; | |||||
} | |||||
} | |||||
} | |||||
} |
#pragma once | |||||
#include "_awaker.h" | |||||
namespace resumef | |||||
{ | |||||
namespace detail | |||||
{ | |||||
struct when_impl; | |||||
typedef _awaker<when_impl> when_awaker; | |||||
typedef std::shared_ptr<when_awaker> when_awaker_ptr; | |||||
struct when_impl : public std::enable_shared_from_this<when_impl> | |||||
{ | |||||
private: | |||||
//typedef spinlock lock_type; | |||||
typedef std::recursive_mutex lock_type; | |||||
when_awaker_ptr _awakes; | |||||
intptr_t _counter; | |||||
lock_type _lock; | |||||
public: | |||||
RF_API when_impl(intptr_t initial_counter_); | |||||
RF_API void signal(); | |||||
RF_API void reset(intptr_t initial_counter_); | |||||
//如果已经触发了awaker,则返回true | |||||
RF_API bool wait_(const when_awaker_ptr & awaker); | |||||
template<class callee_t, class dummy_t = std::enable_if<!std::is_same<std::remove_cv_t<callee_t>, event_awaker_ptr>::value>> | |||||
auto wait(callee_t && awaker, dummy_t * dummy_ = nullptr) | |||||
{ | |||||
return wait_(std::make_shared<event_awaker>(std::forward<callee_t>(awaker))); | |||||
} | |||||
when_impl(const when_impl &) = delete; | |||||
when_impl(when_impl &&) = delete; | |||||
when_impl & operator = (const when_impl &) = delete; | |||||
when_impl & operator = (when_impl &&) = delete; | |||||
}; | |||||
typedef std::shared_ptr<when_impl> when_impl_ptr; | |||||
template<class _Fty> | |||||
struct when_one_functor | |||||
{ | |||||
when_impl_ptr _e; | |||||
mutable future_t<_Fty> _f; | |||||
when_one_functor(const detail::when_impl_ptr & e, future_t<_Fty> f) | |||||
:_e(e) | |||||
, _f(std::move(f)) | |||||
{} | |||||
when_one_functor(when_one_functor &&) = default; | |||||
inline future_vt operator ()() const | |||||
{ | |||||
co_await _f; | |||||
_e->signal(); | |||||
} | |||||
}; | |||||
inline void when_one__(scheduler * s, const detail::when_impl_ptr & e) | |||||
{ | |||||
} | |||||
template<class _Fty, class... _Rest> | |||||
inline void when_one__(scheduler * s, const detail::when_impl_ptr & e, future_t<_Fty> f, _Rest&&... rest) | |||||
{ | |||||
(*s) + when_one_functor<_Fty>{e, std::move(f)}; | |||||
when_one__(s, e, std::forward<_Rest>(rest)...); | |||||
} | |||||
} | |||||
template<class... _Fty> | |||||
future_t<bool> when_count(size_t counter, scheduler * s, _Fty&&... f) | |||||
{ | |||||
promise_t<bool> awaitable; | |||||
detail::when_impl_ptr _event = std::make_shared<detail::when_impl>(counter); | |||||
auto awaker = std::make_shared<detail::when_awaker>( | |||||
[st = awaitable._state](detail::when_impl * e) -> bool | |||||
{ | |||||
st->set_value(e ? true : false); | |||||
return true; | |||||
}); | |||||
_event->wait_(awaker); | |||||
detail::when_one__(s, _event, std::forward<_Fty>(f)...); | |||||
return awaitable.get_future(); | |||||
} | |||||
template<class... _Fty> | |||||
future_t<bool> when_all(scheduler * s, _Fty&&... f) | |||||
{ | |||||
return when_count(sizeof...(_Fty), s, std::forward<_Fty>(f)...); | |||||
} | |||||
template<class... _Fty> | |||||
future_t<bool> when_all(_Fty&&... f) | |||||
{ | |||||
return when_count(sizeof...(_Fty), this_scheduler(), std::forward<_Fty>(f)...); | |||||
} | |||||
template<class... _Fty> | |||||
future_t<bool> when_any(scheduler * s, _Fty&&... f) | |||||
{ | |||||
static_assert(sizeof...(_Fty) > 0); | |||||
return when_count(1, s, std::forward<_Fty>(f)...); | |||||
} | |||||
template<class... _Fty> | |||||
future_t<bool> when_any(_Fty&&... f) | |||||
{ | |||||
static_assert(sizeof...(_Fty) > 0); | |||||
return when_count(1, this_scheduler(), std::forward<_Fty>(f)...); | |||||
} | |||||
} |
//请打开结构化异常(/EHa) | //请打开结构化异常(/EHa) | ||||
auto async_signal_exception(const intptr_t dividend) | auto async_signal_exception(const intptr_t dividend) | ||||
{ | { | ||||
awaitable_t<int64_t> awaitable; | |||||
promise_t<int64_t> awaitable; | |||||
std::thread([dividend, st = awaitable._state] | std::thread([dividend, st = awaitable._state] | ||||
{ | { | ||||
} | } | ||||
}).detach(); | }).detach(); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
auto async_signal_exception2(const intptr_t dividend) | auto async_signal_exception2(const intptr_t dividend) | ||||
{ | { | ||||
awaitable_t<int64_t> awaitable; | |||||
promise_t<int64_t> awaitable; | |||||
std::thread([dividend, st = awaitable._state] | std::thread([dividend, st = awaitable._state] | ||||
{ | { | ||||
st->set_value(10000 / dividend); | st->set_value(10000 / dividend); | ||||
}).detach(); | }).detach(); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
future_vt test_signal_exception() | future_vt test_signal_exception() |
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
awaitable_t<int64_t> awaitable; | |||||
promise_t<int64_t> awaitable; | |||||
std::thread([val, st = awaitable._state] | std::thread([val, st = awaitable._state] | ||||
{ | { | ||||
st->set_value(val * val); | st->set_value(val * val); | ||||
}).detach(); | }).detach(); | ||||
return awaitable; | |||||
return awaitable.get_future(); | |||||
} | } | ||||
future_vt heavy_computing_sequential(int64_t val) | future_vt heavy_computing_sequential(int64_t val) |
| |||||
#include <chrono> | |||||
#include <iostream> | |||||
#include <string> | |||||
#include <conio.h> | |||||
#include <thread> | |||||
#include <experimental/resumable> | |||||
#include "librf.h" | |||||
using namespace resumef; | |||||
void test_when_any() | |||||
{ | |||||
using namespace std::chrono; | |||||
GO | |||||
{ | |||||
co_await when_any( | |||||
[]() ->future_vt | |||||
{ | |||||
auto dt = rand() % 1000; | |||||
co_await sleep_for(1ms * dt); | |||||
std::cout << dt << "@1000" << std::endl; | |||||
}(), | |||||
[]() ->future_vt | |||||
{ | |||||
auto dt = rand() % 2000; | |||||
co_await sleep_for(1ms * dt); | |||||
std::cout << dt << "@2000" << std::endl; | |||||
}(), | |||||
[]() ->future_vt | |||||
{ | |||||
auto dt = rand() % 3000; | |||||
co_await sleep_for(1ms * dt); | |||||
std::cout << dt << "@3000" << std::endl; | |||||
}()); | |||||
std::cout << "any done!" << std::endl; | |||||
}; | |||||
this_scheduler()->run_until_notask(); | |||||
} | |||||
void test_when_all() | |||||
{ | |||||
using namespace std::chrono; | |||||
auto my_sleep = [](const char * name) -> future_vt | |||||
{ | |||||
auto dt = rand() % 1000; | |||||
co_await sleep_for(1ms * dt); | |||||
std::cout << dt << "@" << name << std::endl; | |||||
}; | |||||
GO | |||||
{ | |||||
co_await when_all(); | |||||
std::cout << "zero!" << std::endl; | |||||
co_await when_all(my_sleep("a"), my_sleep("b")); | |||||
co_await my_sleep("c"); | |||||
co_await when_all(my_sleep("d"), my_sleep("e"), my_sleep("f")); | |||||
std::cout << "all done!" << std::endl; | |||||
}; | |||||
this_scheduler()->run_until_notask(); | |||||
} | |||||
void resumable_main_when_all() | |||||
{ | |||||
srand((uint32_t)time(nullptr)); | |||||
test_when_any(); | |||||
std::cout << std::endl; | |||||
test_when_all(); | |||||
} |
extern void resumable_main_cb(); | extern void resumable_main_cb(); | ||||
extern void resumable_main_multi_thread(); | extern void resumable_main_multi_thread(); | ||||
extern void resumable_main_channel_mult_thread(); | extern void resumable_main_channel_mult_thread(); | ||||
extern void resumable_main_when_all(); | |||||
extern void resumable_main_benchmark_mem(); | extern void resumable_main_benchmark_mem(); | ||||
int main(int argc, const char * argv[]) | int main(int argc, const char * argv[]) | ||||
{ | { | ||||
resumable_main_channel_mult_thread(); | |||||
resumable_main_when_all(); | |||||
//resumable_main_multi_thread(); | //resumable_main_multi_thread(); | ||||
return 0; | return 0; | ||||
<SDLCheck>true</SDLCheck> | <SDLCheck>true</SDLCheck> | ||||
<AdditionalIncludeDirectories>..\librf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | <AdditionalIncludeDirectories>..\librf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | ||||
<AdditionalOptions>/await /std:c++latest </AdditionalOptions> | <AdditionalOptions>/await /std:c++latest </AdditionalOptions> | ||||
<MultiProcessorCompilation>true</MultiProcessorCompilation> | |||||
</ClCompile> | </ClCompile> | ||||
<Link> | <Link> | ||||
<SubSystem>Console</SubSystem> | <SubSystem>Console</SubSystem> | ||||
<SDLCheck>true</SDLCheck> | <SDLCheck>true</SDLCheck> | ||||
<AdditionalIncludeDirectories>..\librf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | <AdditionalIncludeDirectories>..\librf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | ||||
<AdditionalOptions>/await /std:c++latest </AdditionalOptions> | <AdditionalOptions>/await /std:c++latest </AdditionalOptions> | ||||
<MultiProcessorCompilation>true</MultiProcessorCompilation> | |||||
</ClCompile> | </ClCompile> | ||||
<Link> | <Link> | ||||
<SubSystem>Console</SubSystem> | <SubSystem>Console</SubSystem> | ||||
<SDLCheck>true</SDLCheck> | <SDLCheck>true</SDLCheck> | ||||
<AdditionalIncludeDirectories>..\librf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | <AdditionalIncludeDirectories>..\librf;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | ||||
<AdditionalOptions>/await /std:c++latest </AdditionalOptions> | <AdditionalOptions>/await /std:c++latest </AdditionalOptions> | ||||
<MultiProcessorCompilation>true</MultiProcessorCompilation> | |||||
</ClCompile> | </ClCompile> | ||||
<Link> | <Link> | ||||
<SubSystem>Console</SubSystem> | <SubSystem>Console</SubSystem> | ||||
<StringPooling>true</StringPooling> | <StringPooling>true</StringPooling> | ||||
<LanguageStandard>stdcpplatest</LanguageStandard> | <LanguageStandard>stdcpplatest</LanguageStandard> | ||||
<BufferSecurityCheck>false</BufferSecurityCheck> | <BufferSecurityCheck>false</BufferSecurityCheck> | ||||
<MultiProcessorCompilation>true</MultiProcessorCompilation> | |||||
</ClCompile> | </ClCompile> | ||||
<Link> | <Link> | ||||
<SubSystem>Console</SubSystem> | <SubSystem>Console</SubSystem> | ||||
<ClCompile Include="..\librf\src\sleep.cpp" /> | <ClCompile Include="..\librf\src\sleep.cpp" /> | ||||
<ClCompile Include="..\librf\src\state.cpp" /> | <ClCompile Include="..\librf\src\state.cpp" /> | ||||
<ClCompile Include="..\librf\src\timer.cpp" /> | <ClCompile Include="..\librf\src\timer.cpp" /> | ||||
<ClCompile Include="..\librf\src\when.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_cb.cpp" /> | <ClCompile Include="..\tutorial\test_async_cb.cpp" /> | ||||
<ClCompile Include="..\tutorial\test_async_channel.cpp" /> | <ClCompile Include="..\tutorial\test_async_channel.cpp" /> | ||||
<ClCompile Include="..\tutorial\test_async_channel_mult_thread.cpp" /> | <ClCompile Include="..\tutorial\test_async_channel_mult_thread.cpp" /> | ||||
<ClCompile Include="..\tutorial\test_async_sleep.cpp" /> | <ClCompile Include="..\tutorial\test_async_sleep.cpp" /> | ||||
<ClCompile Include="..\tutorial\test_async_suspend_always.cpp" /> | <ClCompile Include="..\tutorial\test_async_suspend_always.cpp" /> | ||||
<ClCompile Include="..\tutorial\test_async_timer.cpp" /> | <ClCompile Include="..\tutorial\test_async_timer.cpp" /> | ||||
<ClCompile Include="..\tutorial\test_async_when_all.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_yield_return.cpp" /> | <ClCompile Include="..\tutorial\test_async_yield_return.cpp" /> | ||||
<ClCompile Include="librf.cpp" /> | <ClCompile Include="librf.cpp" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ClInclude Include="..\librf\src\timer.h" /> | <ClInclude Include="..\librf\src\timer.h" /> | ||||
<ClInclude Include="..\librf\src\unix\coroutine.h" /> | <ClInclude Include="..\librf\src\unix\coroutine.h" /> | ||||
<ClInclude Include="..\librf\src\utils.h" /> | <ClInclude Include="..\librf\src\utils.h" /> | ||||
<ClInclude Include="..\librf\src\when.h" /> | |||||
<ClInclude Include="..\librf\src\_awaker.h" /> | <ClInclude Include="..\librf\src\_awaker.h" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
<ClCompile Include="..\tutorial\test_async_channel_mult_thread.cpp"> | <ClCompile Include="..\tutorial\test_async_channel_mult_thread.cpp"> | ||||
<Filter>tutorial</Filter> | <Filter>tutorial</Filter> | ||||
</ClCompile> | </ClCompile> | ||||
<ClCompile Include="..\tutorial\test_async_when_all.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\when.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ClInclude Include="..\librf\librf.h"> | <ClInclude Include="..\librf\librf.h"> | ||||
<ClInclude Include="..\librf\src\counted_ptr.h"> | <ClInclude Include="..\librf\src\counted_ptr.h"> | ||||
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</ClInclude> | </ClInclude> | ||||
<ClInclude Include="..\librf\src\when.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |