{ | { | ||||
auto self = this->shared_from_this(); | auto self = this->shared_from_this(); | ||||
asio::async_connect(socket_, endpoint_, | asio::async_connect(socket_, endpoint_, | ||||
[this, self](std::error_code ec, tcp::resolver::iterator iter) | |||||
[this, self](std::error_code ec, tcp::resolver::iterator ) | |||||
{ | { | ||||
if (!ec) | if (!ec) | ||||
{ | { |
for (size_t i = 0; i < N; ++i) | for (size_t i = 0; i < N; ++i) | ||||
{ | { | ||||
go[=]()->resumef::future_t<size_t> | |||||
go[=]()->resumef::generator_t<size_t> | |||||
{ | { | ||||
for (size_t k = 0; k < 10; ++k) | for (size_t k = 0; k < 10; ++k) | ||||
{ | { |
using typename awaitable_impl_t<_Ty>::value_type; | using typename awaitable_impl_t<_Ty>::value_type; | ||||
using awaitable_impl_t<_Ty>::awaitable_impl_t; | using awaitable_impl_t<_Ty>::awaitable_impl_t; | ||||
void set_value(value_type value) const | |||||
template<class U> | |||||
void set_value(U&& value) const | |||||
{ | { | ||||
this->_state->set_value(std::move(value)); | |||||
this->_state->set_value(std::forward<U>(value)); | |||||
this->_state = nullptr; | this->_state = nullptr; | ||||
} | } | ||||
}; | }; |
#pragma once | #pragma once | ||||
#define LIB_RESUMEF_VERSION 20200 // 2.2.0 | |||||
#define LIB_RESUMEF_VERSION 20201 // 2.2.1 | |||||
#if defined(RESUMEF_MODULE_EXPORT) | #if defined(RESUMEF_MODULE_EXPORT) | ||||
#define RESUMEF_NS export namespace resumef | #define RESUMEF_NS export namespace resumef |
}; | }; | ||||
} | } | ||||
namespace std { | |||||
namespace experimental { | |||||
/*If the coroutine is defined as task<float> foo(std::string x, bool flag);, | |||||
then its Promise type is std::coroutine_traits<task<float>, std::string, bool>::promise_type. | |||||
If the coroutine is a non-static member function, such as task<void> my_class::method1(int x) const;, | |||||
its Promise type is std::coroutine_traits<task<void>, const my_class&, int>::promise_type. | |||||
*/ | |||||
template <typename _Ty, typename... Args> | |||||
struct coroutine_traits<resumef::future_t<_Ty>, Args...> | |||||
{ | |||||
typedef resumef::promise_t<_Ty> promise_type; | |||||
}; | |||||
} | |||||
} // namespace std::experimental | |||||
} | } | ||||
promise_type(promise_type&& _Right) noexcept = default; | promise_type(promise_type&& _Right) noexcept = default; | ||||
promise_type& operator = (promise_type&& _Right) noexcept = default; | promise_type& operator = (promise_type&& _Right) noexcept = default; | ||||
promise_type(const promise_type&) = delete; | |||||
promise_type& operator = (const promise_type&) = delete; | |||||
promise_type(const promise_type&) = default; | |||||
promise_type& operator = (const promise_type&) = default; | |||||
promise_type& get_return_object() | |||||
generator_t get_return_object() | |||||
{ | { | ||||
return *this; | |||||
return generator_t{ *this }; | |||||
} | } | ||||
bool initial_suspend() | bool initial_suspend() | ||||
{ | { | ||||
return (true); | |||||
return true; | |||||
} | } | ||||
bool final_suspend() | bool final_suspend() | ||||
{ | { | ||||
return (true); | |||||
return true; | |||||
} | } | ||||
void yield_value(_Ty const& _Value) | void yield_value(_Ty const& _Value) | ||||
_CurrentValue = std::addressof(_Value); | _CurrentValue = std::addressof(_Value); | ||||
} | } | ||||
template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>> | |||||
//template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>> | |||||
void return_value(_Ty const& _Value) | void return_value(_Ty const& _Value) | ||||
{ | { | ||||
_CurrentValue = std::addressof(_Value); | _CurrentValue = std::addressof(_Value); | ||||
} | } | ||||
template<class = std::enable_if_t<std::is_same_v<_Ty, void>, _Ty>> | |||||
//template<class = std::enable_if_t<std::is_same_v<_Ty, void>, _Ty>> | |||||
void return_value() | void return_value() | ||||
{ | { | ||||
_CurrentValue = nullptr; | _CurrentValue = nullptr; | ||||
} | } | ||||
void set_exception(std::exception_ptr e) | |||||
{ | |||||
std::terminate(); | |||||
} | |||||
#ifdef __clang__ | |||||
void unhandled_exception() | |||||
{ | |||||
std::terminate(); | |||||
} | |||||
#endif | |||||
template <typename _Uty> | template <typename _Uty> | ||||
_Uty&& await_transform(_Uty&& _Whatever) | _Uty&& await_transform(_Uty&& _Whatever) | ||||
{ | { | ||||
*reinterpret_cast<uint32_t*>(_Ptr) = static_cast<uint32_t>(_Size + _State_size); | *reinterpret_cast<uint32_t*>(_Ptr) = static_cast<uint32_t>(_Size + _State_size); | ||||
_Alloc_char _Al; | |||||
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size); | state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size); | ||||
st->unlock(); | st->unlock(); | ||||
} | } | ||||
generator_t() = default; | generator_t() = default; | ||||
generator_t(generator_t const&) = delete; | generator_t(generator_t const&) = delete; | ||||
generator_t& operator=(generator_t const&) = delete; | generator_t& operator=(generator_t const&) = delete; | ||||
generator_t(generator_t&& right_) noexcept | generator_t(generator_t&& right_) noexcept | ||||
#pragma pop_macro("new") | #pragma pop_macro("new") | ||||
#pragma pack(pop) | #pragma pack(pop) | ||||
namespace std { | |||||
namespace experimental { | |||||
template <typename _Ty, typename _Alloc, typename... Args> | |||||
struct coroutine_traits<resumef::generator_t<_Ty, _Alloc>, Args...> | |||||
{ | |||||
typedef typename resumef::generator_t<_Ty, _Alloc>::promise_type promise_type; | |||||
}; | |||||
} | |||||
} // namespace std::experimental |
suspend_on_final final_suspend() noexcept; | suspend_on_final final_suspend() noexcept; | ||||
void set_exception(std::exception_ptr e); | void set_exception(std::exception_ptr e); | ||||
#ifdef __clang__ | #ifdef __clang__ | ||||
void unhandled_exception(); | |||||
void unhandled_exception(); //If the coroutine ends with an uncaught exception, it performs the following: | |||||
#endif | #endif | ||||
future_type get_return_object(); | future_type get_return_object(); | ||||
void cancellation_requested(); | void cancellation_requested(); | ||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | ||||
_Alloc_char _Al; | _Alloc_char _Al; | ||||
/*If allocation fails, the coroutine throws std::bad_alloc, | |||||
unless the Promise type defines the member function Promise::get_return_object_on_allocation_failure(). | |||||
If that member function is defined, allocation uses the nothrow form of operator new and on allocation failure, | |||||
the coroutine immediately returns the object obtained from Promise::get_return_object_on_allocation_failure() to the caller. | |||||
*/ | |||||
char* ptr = _Al.allocate(_Size + _State_size); | char* ptr = _Al.allocate(_Size + _State_size); | ||||
#if RESUMEF_DEBUG_COUNTER | #if RESUMEF_DEBUG_COUNTER | ||||
std::cout << " future_promise::new, alloc size=" << (_Size + _State_size) << std::endl; | std::cout << " future_promise::new, alloc size=" << (_Size + _State_size) << std::endl; | ||||
size_t _State_size = _Align_size<state_type>(); | size_t _State_size = _Align_size<state_type>(); | ||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | ||||
_Alloc_char _Al; | |||||
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size); | state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size); | ||||
st->unlock(); | st->unlock(); | ||||
} | } | ||||
using typename promise_impl_t<_Ty>::value_type; | using typename promise_impl_t<_Ty>::value_type; | ||||
using promise_impl_t<_Ty>::get_return_object; | using promise_impl_t<_Ty>::get_return_object; | ||||
void return_value(value_type val); | |||||
void yield_value(value_type val); | |||||
template<class U> | |||||
void return_value(U&& val); //co_return val | |||||
template<class U> | |||||
void yield_value(U&& val); | |||||
}; | }; | ||||
template<> | template<> | ||||
{ | { | ||||
using promise_impl_t<void>::get_return_object; | using promise_impl_t<void>::get_return_object; | ||||
void return_void(); | |||||
void return_void(); //co_return; | |||||
void yield_value(); | void yield_value(); | ||||
}; | }; | ||||
| | ||||
RESUMEF_NS | RESUMEF_NS | ||||
{ | { | ||||
/* | |||||
Note: the awaiter object is part of coroutine state (as a temporary whose lifetime crosses a suspension point) | |||||
and is destroyed before the co_await expression finishes. | |||||
It can be used to maintain per-operation state as required by some async I/O APIs without resorting to additional heap allocations. | |||||
*/ | |||||
struct suspend_on_initial | struct suspend_on_initial | ||||
{ | { | ||||
state_future_t* _state; | |||||
inline bool await_ready() noexcept | inline bool await_ready() noexcept | ||||
{ | { | ||||
return false; | return false; | ||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | ||||
inline void await_suspend(coroutine_handle<_PromiseT> handler) noexcept | inline void await_suspend(coroutine_handle<_PromiseT> handler) noexcept | ||||
{ | { | ||||
_PromiseT& promise = handler.promise(); | |||||
auto* _state = promise.get_state(); | |||||
_state->promise_initial_suspend(handler); | _state->promise_initial_suspend(handler); | ||||
} | } | ||||
inline void await_resume() noexcept | inline void await_resume() noexcept | ||||
{ | { | ||||
_state->promise_await_resume(); | |||||
} | } | ||||
}; | }; | ||||
struct suspend_on_final | struct suspend_on_final | ||||
{ | { | ||||
state_future_t* _state; | |||||
inline bool await_ready() noexcept | inline bool await_ready() noexcept | ||||
{ | { | ||||
return false; | return false; | ||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | ||||
inline void await_suspend(coroutine_handle<_PromiseT> handler) noexcept | inline void await_suspend(coroutine_handle<_PromiseT> handler) noexcept | ||||
{ | { | ||||
_PromiseT& promise = handler.promise(); | |||||
auto* _state = promise.get_state(); | |||||
_state->promise_final_suspend(handler); | _state->promise_final_suspend(handler); | ||||
} | } | ||||
inline void await_resume() noexcept | inline void await_resume() noexcept | ||||
{ | { | ||||
_state->promise_await_resume(); | |||||
} | } | ||||
}; | }; | ||||
template <typename _Ty> | template <typename _Ty> | ||||
inline suspend_on_initial promise_impl_t<_Ty>::initial_suspend() noexcept | inline suspend_on_initial promise_impl_t<_Ty>::initial_suspend() noexcept | ||||
{ | { | ||||
return { this->get_state() }; | |||||
return {}; | |||||
} | } | ||||
template <typename _Ty> | template <typename _Ty> | ||||
inline suspend_on_final promise_impl_t<_Ty>::final_suspend() noexcept | inline suspend_on_final promise_impl_t<_Ty>::final_suspend() noexcept | ||||
{ | { | ||||
return { this->get_state() }; | |||||
return {}; | |||||
} | } | ||||
template <typename _Ty> | template <typename _Ty> | ||||
template <typename _Ty> | template <typename _Ty> | ||||
inline void promise_impl_t<_Ty>::unhandled_exception() | inline void promise_impl_t<_Ty>::unhandled_exception() | ||||
{ | { | ||||
std::terminate(); | |||||
this->get_state()->set_exception(std::current_exception()); | |||||
} | } | ||||
#endif | #endif | ||||
template<class _Ty> | template<class _Ty> | ||||
inline void promise_t<_Ty>::return_value(value_type val) | |||||
template<class U> | |||||
inline void promise_t<_Ty>::return_value(U&& val) | |||||
{ | { | ||||
this->get_state()->set_value(std::move(val)); | |||||
this->get_state()->set_value(std::forward<U>(val)); | |||||
} | } | ||||
template<class _Ty> | template<class _Ty> | ||||
inline void promise_t<_Ty>::yield_value(value_type val) | |||||
template<class U> | |||||
inline void promise_t<_Ty>::yield_value(U&& val) | |||||
{ | { | ||||
this->get_state()->promise_yield_value(this, std::move(val)); | |||||
this->get_state()->promise_yield_value(this, std::forward<U>(val)); | |||||
} | } | ||||
inline void promise_t<void>::return_void() | inline void promise_t<void>::return_void() |
{ | { | ||||
std::unique_lock<lock_type> __guard(_mtx); | std::unique_lock<lock_type> __guard(_mtx); | ||||
if (_initor != nullptr && _is_initor) | |||||
if (_is_initor == initor_type::Initial) | |||||
{ | { | ||||
coroutine_handle<> handler = _initor; | |||||
_initor = nullptr; | |||||
assert(_initor != nullptr); | |||||
_is_initor = initor_type::None; | |||||
__guard.unlock(); | __guard.unlock(); | ||||
handler.resume(); | |||||
_initor.resume(); | |||||
return; | return; | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
if (_initor != nullptr && !_is_initor) | |||||
if (_is_initor == initor_type::Final) | |||||
{ | { | ||||
coroutine_handle<> handler = _initor; | |||||
_initor = nullptr; | |||||
_is_initor = initor_type::None; | |||||
__guard.unlock(); | __guard.unlock(); | ||||
handler.destroy(); | |||||
_initor.destroy(); | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
bool state_future_t::has_handler() const | bool state_future_t::has_handler() const | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(_mtx); | scoped_lock<lock_type> __guard(_mtx); | ||||
return _coro != nullptr || _initor != nullptr; | |||||
return _coro != nullptr || _is_initor != initor_type::None; | |||||
} | } | ||||
bool state_future_t::is_ready() const | bool state_future_t::is_ready() const |
struct state_future_t : public state_base_t | struct state_future_t : public state_base_t | ||||
{ | { | ||||
enum struct initor_type : uint8_t | |||||
{ | |||||
None, | |||||
Initial, | |||||
Final | |||||
}; | |||||
typedef std::recursive_mutex lock_type; | typedef std::recursive_mutex lock_type; | ||||
protected: | protected: | ||||
mutable lock_type _mtx; | mutable lock_type _mtx; | ||||
uint32_t _alloc_size; | uint32_t _alloc_size; | ||||
bool _has_value = false; | bool _has_value = false; | ||||
bool _is_awaitor; | bool _is_awaitor; | ||||
bool _is_initor = false; | |||||
initor_type _is_initor = initor_type::None; | |||||
public: | public: | ||||
state_future_t() | state_future_t() | ||||
{ | { | ||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | ||||
void promise_initial_suspend(coroutine_handle<_PromiseT> handler); | void promise_initial_suspend(coroutine_handle<_PromiseT> handler); | ||||
void promise_await_resume(); | |||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | ||||
void promise_final_suspend(coroutine_handle<_PromiseT> handler); | void promise_final_suspend(coroutine_handle<_PromiseT> handler); | ||||
}; | }; | ||||
{ | { | ||||
_alloc_size = sizeof(*this); | _alloc_size = sizeof(*this); | ||||
} | } | ||||
private: | |||||
union union_value_type | |||||
{ | |||||
value_type _value; | |||||
char _[1]; | |||||
union_value_type() {} | |||||
~union_value_type() {} | |||||
}; | |||||
union_value_type uv; | |||||
~state_t() | ~state_t() | ||||
{ | { | ||||
if (_has_value) | if (_has_value) | ||||
uv._value.~value_type(); | |||||
cast_value_ptr()->~value_type(); | |||||
} | } | ||||
public: | |||||
auto future_await_resume() -> value_type; | auto future_await_resume() -> value_type; | ||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | |||||
void promise_yield_value(_PromiseT* promise, value_type val); | |||||
template<class _PromiseT, typename U, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | |||||
void promise_yield_value(_PromiseT* promise, U&& val); | |||||
template<typename U> | |||||
void set_value(U&& val); | |||||
private: | |||||
value_type * cast_value_ptr() | |||||
{ | |||||
return static_cast<value_type*>(static_cast<void*>(_value)); | |||||
} | |||||
void set_value(value_type val); | |||||
alignas(value_type) unsigned char _value[sizeof(value_type)]; | |||||
}; | }; | ||||
template<> | template<> |
template<class _PromiseT, typename _Enable> | template<class _PromiseT, typename _Enable> | ||||
void state_future_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler) | void state_future_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler) | ||||
{ | { | ||||
_PromiseT& promise = handler.promise(); | |||||
state_base_t* parent_state = promise.get_state(); | |||||
(void)parent_state; | |||||
assert(this == parent_state); | |||||
assert(this->_scheduler == nullptr); | assert(this->_scheduler == nullptr); | ||||
assert(this->_coro == nullptr); | assert(this->_coro == nullptr); | ||||
this->_initor = handler; | |||||
this->_is_initor = true; | |||||
} | |||||
inline void state_future_t::promise_await_resume() | |||||
{ | |||||
this->_initor = handler; | |||||
this->_is_initor = initor_type::Initial; | |||||
} | } | ||||
template<class _PromiseT, typename _Enable> | template<class _PromiseT, typename _Enable> | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(this->_mtx); | scoped_lock<lock_type> __guard(this->_mtx); | ||||
_PromiseT& promise = handler.promise(); | |||||
state_base_t* parent_state = promise.get_state(); | |||||
(void)parent_state; | |||||
assert(this == parent_state); | |||||
this->_initor = handler; | this->_initor = handler; | ||||
this->_is_initor = false; | |||||
this->_is_initor = initor_type::Final; | |||||
scheduler_t* sch = this->get_scheduler(); | scheduler_t* sch = this->get_scheduler(); | ||||
assert(sch != nullptr); | assert(sch != nullptr); | ||||
} | } | ||||
template<typename _Ty> | template<typename _Ty> | ||||
template<class _PromiseT, typename _Enable > | |||||
void state_t<_Ty>::promise_yield_value(_PromiseT* promise, _Ty val) | |||||
template<class _PromiseT, typename U, typename _Enable > | |||||
void state_t<_Ty>::promise_yield_value(_PromiseT* promise, U&& val) | |||||
{ | { | ||||
scoped_lock<lock_type> __guard(this->_mtx); | scoped_lock<lock_type> __guard(this->_mtx); | ||||
if (this->_has_value) | if (this->_has_value) | ||||
{ | { | ||||
this->uv._value = std::move(val); | |||||
*this->cast_value_ptr() = std::forward<U>(val); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
new (this->cast_value_ptr()) value_type(std::forward<U>(val)); | |||||
this->_has_value = true; | this->_has_value = true; | ||||
new(&this->uv._value) value_type(std::move(val)); | |||||
} | } | ||||
coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise); | coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise); | ||||
if (!this->_has_value) | if (!this->_has_value) | ||||
std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready})); | std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready})); | ||||
return std::move(this->uv._value); | |||||
return std::move(*this->cast_value_ptr()); | |||||
} | } | ||||
template<typename _Ty> | template<typename _Ty> | ||||
void state_t<_Ty>::set_value(value_type val) | |||||
template<typename U> | |||||
void state_t<_Ty>::set_value(U&& val) | |||||
{ | { | ||||
scoped_lock<lock_type> __guard(this->_mtx); | scoped_lock<lock_type> __guard(this->_mtx); | ||||
if (this->_has_value) | if (this->_has_value) | ||||
{ | { | ||||
this->uv._value = std::move(val); | |||||
*this->cast_value_ptr() = std::forward<U>(val); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
new (this->cast_value_ptr()) value_type(std::forward<U>(val)); | |||||
this->_has_value = true; | this->_has_value = true; | ||||
new(&this->uv._value) value_type(std::move(val)); | |||||
} | } | ||||
scheduler_t* sch = this->get_scheduler(); | scheduler_t* sch = this->get_scheduler(); |
#endif | #endif | ||||
std::cout << std::endl; | std::cout << std::endl; | ||||
} | } | ||||
catch (channel_exception e) | |||||
catch (resumef::channel_exception& e) | |||||
{ | { | ||||
//MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常 | //MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常 | ||||
std::cout << e.what() << std::endl; | std::cout << e.what() << std::endl; |
} | } | ||||
#endif | #endif | ||||
} | } | ||||
catch (channel_exception e) | |||||
catch (channel_exception& e) | |||||
{ | { | ||||
//MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常 | //MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常 | ||||
scoped_lock<std::mutex> __lock(cout_mutex); | scoped_lock<std::mutex> __lock(cout_mutex); |
go[&]() -> future_t<> | go[&]() -> future_t<> | ||||
{ | { | ||||
for (int i = 0; i < _countof(evts); ++i) | |||||
for (size_t i = 0; i < _countof(evts); ++i) | |||||
{ | { | ||||
intptr_t idx = co_await event_t::wait_any(evts); | intptr_t idx = co_await event_t::wait_any(evts); | ||||
std::cout << "event " << idx << " signal!" << std::endl; | std::cout << "event " << idx << " signal!" << std::endl; |
//适配器类型 | //适配器类型 | ||||
using _Adapter_t = modern_callback_adapter_t<typename resumef::remove_cvref_t<_Callable_t>, void(std::string)>; | using _Adapter_t = modern_callback_adapter_t<typename resumef::remove_cvref_t<_Callable_t>, void(std::string)>; | ||||
//通过适配器获得兼容_Signature_t类型的真正的回调,以及返回值_Return_t | //通过适配器获得兼容_Signature_t类型的真正的回调,以及返回值_Return_t | ||||
auto adapter = typename _Adapter_t::traits(std::forward<_Callable_t>(token)); | |||||
auto adapter = _Adapter_t::traits(std::forward<_Callable_t>(token)); | |||||
//callback与token未必是同一个变量,甚至未必是同一个类型 | //callback与token未必是同一个变量,甚至未必是同一个类型 | ||||
std::thread([callback = std::move(std::get<0>(adapter)), value = std::forward<_Input_t>(value)] | std::thread([callback = std::move(std::get<0>(adapter)), value = std::forward<_Input_t>(value)] | ||||
//或者宏版本写法 | //或者宏版本写法 | ||||
#define MODERN_CALLBACK_TRAITS(_Token_value, _Signature_t) \ | #define MODERN_CALLBACK_TRAITS(_Token_value, _Signature_t) \ | ||||
using _Adapter_t = modern_callback_adapter_t<typename resumef::remove_cvref_t<_Callable_t>, _Signature_t>; \ | using _Adapter_t = modern_callback_adapter_t<typename resumef::remove_cvref_t<_Callable_t>, _Signature_t>; \ | ||||
auto _Adapter_value = typename _Adapter_t::traits(std::forward<_Callable_t>(_Token_value)) | |||||
auto _Adapter_value = _Adapter_t::traits(std::forward<_Callable_t>(_Token_value)) | |||||
#define MODERN_CALLBACK_CALL() std::move(std::get<0>(_Adapter_value)) | #define MODERN_CALLBACK_CALL() std::move(std::get<0>(_Adapter_value)) | ||||
#define MODERN_CALLBACK_RETURN() return std::move(std::get<1>(_Adapter_value)).get() | #define MODERN_CALLBACK_RETURN() return std::move(std::get<1>(_Adapter_value)).get() | ||||
auto get_future() const | auto get_future() const | ||||
{ | { | ||||
return _promise.get_future(); | |||||
return this->_promise.get_future(); | |||||
} | } | ||||
}; | }; | ||||
void operator()() const | void operator()() const | ||||
{ | { | ||||
_promise.set_value(); | |||||
this->_promise.set_value(); | |||||
} | } | ||||
}; | }; | ||||
void operator()(std::exception_ptr eptr) const | void operator()(std::exception_ptr eptr) const | ||||
{ | { | ||||
if (!eptr) | if (!eptr) | ||||
_promise.set_value(); | |||||
this->_promise.set_value(); | |||||
else | else | ||||
_promise.set_exception(std::move(eptr)); | |||||
this->_promise.set_exception(std::move(eptr)); | |||||
} | } | ||||
}; | }; | ||||
template<typename Arg> | template<typename Arg> | ||||
void operator()(Arg && arg) const | void operator()(Arg && arg) const | ||||
{ | { | ||||
_promise.set_value(std::forward<Arg>(arg)); | |||||
this->_promise.set_value(std::forward<Arg>(arg)); | |||||
} | } | ||||
}; | }; | ||||
void operator()(std::exception_ptr eptr, Arg && arg) const | void operator()(std::exception_ptr eptr, Arg && arg) const | ||||
{ | { | ||||
if (!eptr) | if (!eptr) | ||||
_promise.set_value(std::forward<Arg>(arg)); | |||||
this->_promise.set_value(std::forward<Arg>(arg)); | |||||
else | else | ||||
_promise.set_exception(std::move(eptr)); | |||||
this->_promise.set_exception(std::move(eptr)); | |||||
} | } | ||||
}; | }; | ||||
void operator()(Args&&... args) const | void operator()(Args&&... args) const | ||||
{ | { | ||||
static_assert(sizeof...(Args) == sizeof...(_Result_t), ""); | static_assert(sizeof...(Args) == sizeof...(_Result_t), ""); | ||||
_promise.set_value(std::make_tuple(std::forward<Args>(args)...)); | |||||
this->_promise.set_value(std::make_tuple(std::forward<Args>(args)...)); | |||||
} | } | ||||
}; | }; | ||||
{ | { | ||||
static_assert(sizeof...(Args) == sizeof...(_Result_t), ""); | static_assert(sizeof...(Args) == sizeof...(_Result_t), ""); | ||||
if (!eptr) | if (!eptr) | ||||
_promise.set_value(std::make_tuple(std::forward<Args>(args)...)); | |||||
this->_promise.set_value(std::make_tuple(std::forward<Args>(args)...)); | |||||
else | else | ||||
_promise.set_exception(std::move(eptr)); | |||||
this->_promise.set_exception(std::move(eptr)); | |||||
} | } | ||||
}; | }; | ||||
using namespace resumef; | using namespace resumef; | ||||
future_t<> test_loop_sleep(size_t _N, char * ch) | |||||
future_t<> test_loop_sleep(size_t _N, const char * ch) | |||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
//循环直到sch_in_thread为nullptr | //循环直到sch_in_thread为nullptr | ||||
for (;;) | for (;;) | ||||
{ | { | ||||
auto sch = sch_in_thread.load(std::memory_order::acquire); | |||||
auto sch = sch_in_thread.load(std::memory_order_acquire); | |||||
if (sch == nullptr) | if (sch == nullptr) | ||||
break; | break; | ||||
sch->run_one_batch(); | sch->run_one_batch(); | ||||
//这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | //这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | ||||
static future_t<int64_t> async_get_long(int64_t val) | static future_t<int64_t> async_get_long(int64_t val) | ||||
{ | { | ||||
resumef::awaitable_t<int64_t> awaitable; | |||||
awaitable_t<int64_t> awaitable; | |||||
callback_get_long(val, [awaitable](int64_t val) | callback_get_long(val, [awaitable](int64_t val) | ||||
{ | { | ||||
awaitable.set_value(val); | awaitable.set_value(val); |
co_await sleep_for(1ms * dt); | co_await sleep_for(1ms * dt); | ||||
std::cout << dt << "@a" << std::endl; | std::cout << dt << "@a" << std::endl; | ||||
return dt; | |||||
co_return dt; | |||||
}(), | }(), | ||||
[]() ->future_t<> | []() ->future_t<> | ||||
{ | { | ||||
co_await sleep_for(1ms * dt); | co_await sleep_for(1ms * dt); | ||||
std::cout << dt << "@" << name << std::endl; | std::cout << dt << "@" << name << std::endl; | ||||
return dt; | |||||
co_return dt; | |||||
}; | }; | ||||
std::vector<future_t<int> > v{ my_sleep("g"), my_sleep("h"), my_sleep("i") }; | std::vector<future_t<int> > v{ my_sleep("g"), my_sleep("h"), my_sleep("i") }; | ||||
co_await sleep_for(1ms * dt); | co_await sleep_for(1ms * dt); | ||||
std::cout << dt << "@" << name << std::endl; | std::cout << dt << "@" << name << std::endl; | ||||
return dt; | |||||
co_return dt; | |||||
}; | }; | ||||
auto my_sleep_v = [](const char * name) -> future_t<> | auto my_sleep_v = [](const char * name) -> future_t<> |
#include <experimental/resumable> | #include <experimental/resumable> | ||||
#include <experimental/generator> | #include <experimental/generator> | ||||
#include <optional> | #include <optional> | ||||
#include "async_wrapper.hpp" | |||||
extern void resumable_main_yield_return(); | extern void resumable_main_yield_return(); | ||||
extern void resumable_main_timer(); | extern void resumable_main_timer(); | ||||
{ | { | ||||
(void)argc; | (void)argc; | ||||
(void)argv; | (void)argv; | ||||
resumable_main_switch_scheduler(); | |||||
resumable_main_layout(); | |||||
//if (argc > 1) | //if (argc > 1) | ||||
// resumable_main_benchmark_asio_client(atoi(argv[1])); | // resumable_main_benchmark_asio_client(atoi(argv[1])); |
<ProjectGuid>{C1D4A6BD-592F-4E48-8178-7C87219BF80E}</ProjectGuid> | <ProjectGuid>{C1D4A6BD-592F-4E48-8178-7C87219BF80E}</ProjectGuid> | ||||
<Keyword>Win32Proj</Keyword> | <Keyword>Win32Proj</Keyword> | ||||
<RootNamespace>librf</RootNamespace> | <RootNamespace>librf</RootNamespace> | ||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> | ||||
<CLanguageStandard>c11</CLanguageStandard> | <CLanguageStandard>c11</CLanguageStandard> | ||||
<CppLanguageStandard>c++1y</CppLanguageStandard> | <CppLanguageStandard>c++1y</CppLanguageStandard> | ||||
<DisableSpecificWarnings>4834</DisableSpecificWarnings> | <DisableSpecificWarnings>4834</DisableSpecificWarnings> | ||||
<EnableModules>true</EnableModules> | |||||
</ClCompile> | </ClCompile> | ||||
<Link> | <Link> | ||||
<SubSystem>Console</SubSystem> | <SubSystem>Console</SubSystem> |