@@ -20,7 +20,7 @@ static future_t<> passing_next(int_channel_ptr rd, int_channel_ptr wr) | |||
for (;;) | |||
{ | |||
intptr_t value = co_await *rd; | |||
co_await (*wr << (value + 1)); | |||
co_await wr->write(value + 1); | |||
} | |||
} | |||
@@ -39,7 +39,7 @@ RESUMEF_NS | |||
}; | |||
template<class _Ty> | |||
struct awaitable_t : public awaitable_impl_t<_Ty> | |||
struct [[nodiscard]] awaitable_t : public awaitable_impl_t<_Ty> | |||
{ | |||
using typename awaitable_impl_t<_Ty>::value_type; | |||
using awaitable_impl_t<_Ty>::awaitable_impl_t; | |||
@@ -52,8 +52,21 @@ RESUMEF_NS | |||
} | |||
}; | |||
template<class _Ty> | |||
struct [[nodiscard]] awaitable_t<_Ty&> : public awaitable_impl_t<_Ty&> | |||
{ | |||
using typename awaitable_impl_t<_Ty&>::value_type; | |||
using awaitable_impl_t<_Ty&>::awaitable_impl_t; | |||
void set_value(_Ty& value) const | |||
{ | |||
this->_state->set_value(value); | |||
this->_state = nullptr; | |||
} | |||
}; | |||
template<> | |||
struct awaitable_t<void> : public awaitable_impl_t<void> | |||
struct [[nodiscard]] awaitable_t<void> : public awaitable_impl_t<void> | |||
{ | |||
using awaitable_impl_t<void>::awaitable_impl_t; | |||
@@ -1,6 +1,6 @@ | |||
#pragma once | |||
#define LIB_RESUMEF_VERSION 20303 // 2.3.3 | |||
#define LIB_RESUMEF_VERSION 20304 // 2.3.4 | |||
#if defined(RESUMEF_MODULE_EXPORT) | |||
#define RESUMEF_NS export namespace resumef |
@@ -353,4 +353,61 @@ RESUMEF_NS | |||
return awaitable.get_future(); | |||
} | |||
void async_manual_reset_event::set() noexcept | |||
{ | |||
// Needs to be 'release' so that subsequent 'co_await' has | |||
// visibility of our prior writes. | |||
// Needs to be 'acquire' so that we have visibility of prior | |||
// writes by awaiting coroutines. | |||
void* oldValue = m_state.exchange(this, std::memory_order_acq_rel); | |||
if (oldValue != this) | |||
{ | |||
// Wasn't already in 'set' state. | |||
// Treat old value as head of a linked-list of waiters | |||
// which we have now acquired and need to resume. | |||
auto* waiters = static_cast<awaiter*>(oldValue); | |||
while (waiters != nullptr) | |||
{ | |||
// Read m_next before resuming the coroutine as resuming | |||
// the coroutine will likely destroy the awaiter object. | |||
auto* next = waiters->m_next; | |||
waiters->m_awaitingCoroutine.resume(); | |||
waiters = next; | |||
} | |||
} | |||
} | |||
bool async_manual_reset_event::awaiter::await_suspend( | |||
coroutine_handle<> awaitingCoroutine) noexcept | |||
{ | |||
// Special m_state value that indicates the event is in the 'set' state. | |||
const void* const setState = &m_event; | |||
// Remember the handle of the awaiting coroutine. | |||
m_awaitingCoroutine = awaitingCoroutine; | |||
// Try to atomically push this awaiter onto the front of the list. | |||
void* oldValue = m_event.m_state.load(std::memory_order_acquire); | |||
do | |||
{ | |||
// Resume immediately if already in 'set' state. | |||
if (oldValue == setState) return false; | |||
// Update linked list to point at current head. | |||
m_next = static_cast<awaiter*>(oldValue); | |||
// Finally, try to swap the old list head, inserting this awaiter | |||
// as the new list head. | |||
} while (!m_event.m_state.compare_exchange_weak( | |||
oldValue, | |||
this, | |||
std::memory_order_release, | |||
std::memory_order_acquire)); | |||
// Successfully enqueued. Remain suspended. | |||
return true; | |||
} | |||
} |
@@ -208,4 +208,63 @@ RESUMEF_NS | |||
static future_t<bool> wait_all_until_(const clock_type::time_point& tp, std::vector<event_impl_ptr>&& evts); | |||
}; | |||
class async_manual_reset_event | |||
{ | |||
public: | |||
async_manual_reset_event(bool initiallySet = false) noexcept | |||
: m_state(initiallySet ? this : nullptr) | |||
{} | |||
// No copying/moving | |||
async_manual_reset_event(const async_manual_reset_event&) = delete; | |||
async_manual_reset_event(async_manual_reset_event&&) = delete; | |||
async_manual_reset_event& operator=(const async_manual_reset_event&) = delete; | |||
async_manual_reset_event& operator=(async_manual_reset_event&&) = delete; | |||
bool is_set() const noexcept | |||
{ | |||
return m_state.load(std::memory_order_acquire) == this; | |||
} | |||
struct awaiter; | |||
awaiter operator co_await() const noexcept; | |||
void set() noexcept; | |||
void reset() noexcept | |||
{ | |||
void* oldValue = this; | |||
m_state.compare_exchange_strong(oldValue, nullptr, std::memory_order_acquire); | |||
} | |||
private: | |||
friend struct awaiter; | |||
// - 'this' => set state | |||
// - otherwise => not set, head of linked list of awaiter*. | |||
mutable std::atomic<void*> m_state; | |||
}; | |||
struct async_manual_reset_event::awaiter | |||
{ | |||
awaiter(const async_manual_reset_event& event) noexcept | |||
: m_event(event) | |||
{} | |||
bool await_ready() const noexcept | |||
{ | |||
return m_event.is_set(); | |||
} | |||
bool await_suspend(coroutine_handle<> awaitingCoroutine) noexcept; | |||
void await_resume() noexcept {} | |||
private: | |||
friend class async_manual_reset_event; | |||
const async_manual_reset_event& m_event; | |||
coroutine_handle<> m_awaitingCoroutine; | |||
awaiter* m_next; | |||
}; | |||
inline async_manual_reset_event::awaiter async_manual_reset_event::operator co_await() const noexcept | |||
{ | |||
return awaiter{ *this }; | |||
} | |||
} |
@@ -4,7 +4,7 @@ | |||
RESUMEF_NS | |||
{ | |||
template<class _Ty> | |||
struct future_t | |||
struct [[nodiscard]] future_t | |||
{ | |||
using value_type = _Ty; | |||
using state_type = state_t<value_type>; |
@@ -56,6 +56,16 @@ RESUMEF_NS | |||
std::experimental::suspend_always yield_value(U&& val); | |||
}; | |||
template<class _Ty> | |||
struct promise_t<_Ty&> final : public promise_impl_t<_Ty&> | |||
{ | |||
using typename promise_impl_t<_Ty&>::value_type; | |||
using promise_impl_t<_Ty&>::get_return_object; | |||
void return_value(_Ty& val); //co_return val | |||
std::experimental::suspend_always yield_value(_Ty& val); | |||
}; | |||
template<> | |||
struct promise_t<void> final : public promise_impl_t<void> | |||
{ |
@@ -182,6 +182,19 @@ RESUMEF_NS | |||
return {}; | |||
} | |||
template<class _Ty> | |||
inline void promise_t<_Ty&>::return_value(_Ty& val) | |||
{ | |||
this->get_state()->set_value(val); | |||
} | |||
template<class _Ty> | |||
inline std::experimental::suspend_always promise_t<_Ty&>::yield_value(_Ty& val) | |||
{ | |||
this->get_state()->promise_yield_value(this, val); | |||
return {}; | |||
} | |||
inline void promise_t<void>::return_void() | |||
{ | |||
this->get_state()->set_value(); |
@@ -126,21 +126,6 @@ RESUMEF_NS | |||
return has_handler_skip_lock(); | |||
} | |||
void state_future_t::set_exception(std::exception_ptr e) | |||
{ | |||
scoped_lock<lock_type> __guard(this->_mtx); | |||
this->_exception = std::move(e); | |||
scheduler_t* sch = this->get_scheduler(); | |||
if (sch != nullptr) | |||
{ | |||
if (this->has_handler_skip_lock()) | |||
sch->add_generator(this); | |||
else | |||
sch->del_final(this); | |||
} | |||
} | |||
bool state_future_t::switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<> handler) | |||
{ | |||
assert(sch != nullptr); | |||
@@ -177,14 +162,29 @@ RESUMEF_NS | |||
if (this->_exception) | |||
std::rethrow_exception(std::move(this->_exception)); | |||
if (!this->_has_value.load(std::memory_order_acquire)) | |||
if (this->_has_value.load(std::memory_order_acquire) == result_type::None) | |||
std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready})); | |||
} | |||
void state_t<void>::set_value() | |||
{ | |||
scoped_lock<lock_type> __guard(this->_mtx); | |||
this->_has_value.store(true, std::memory_order_release); | |||
this->_has_value.store(result_type::Value, std::memory_order_release); | |||
scheduler_t* sch = this->get_scheduler(); | |||
if (sch != nullptr) | |||
{ | |||
if (this->has_handler_skip_lock()) | |||
sch->add_generator(this); | |||
else | |||
sch->del_final(this); | |||
} | |||
} | |||
void state_t<void>::set_exception(std::exception_ptr e) | |||
{ | |||
scoped_lock<lock_type> __guard(this->_mtx); | |||
this->_exception = std::move(e); | |||
scheduler_t* sch = this->get_scheduler(); | |||
if (sch != nullptr) |
@@ -79,6 +79,13 @@ RESUMEF_NS | |||
Initial, | |||
Final | |||
}; | |||
enum struct result_type : uint8_t | |||
{ | |||
None, | |||
Value, | |||
Exception, | |||
}; | |||
//typedef std::recursive_mutex lock_type; | |||
typedef spinlock lock_type; | |||
protected: | |||
@@ -88,9 +95,8 @@ RESUMEF_NS | |||
#if RESUMEF_DEBUG_COUNTER | |||
intptr_t _id; | |||
#endif | |||
std::exception_ptr _exception; | |||
uint32_t _alloc_size = 0; | |||
std::atomic<bool> _has_value{ false }; | |||
std::atomic<result_type> _has_value{ result_type::None }; | |||
bool _is_awaitor; | |||
initor_type _is_initor = initor_type::None; | |||
public: | |||
@@ -115,7 +121,7 @@ RESUMEF_NS | |||
inline bool is_ready() const | |||
{ | |||
return _exception != nullptr || _has_value.load(std::memory_order_acquire) || !_is_awaitor; | |||
return _has_value.load(std::memory_order_acquire) != result_type::None || !_is_awaitor; | |||
} | |||
inline bool has_handler_skip_lock() const | |||
{ | |||
@@ -136,18 +142,10 @@ RESUMEF_NS | |||
return _alloc_size; | |||
} | |||
void set_exception(std::exception_ptr e); | |||
template<class _Exp> | |||
inline void throw_exception(_Exp e) | |||
{ | |||
set_exception(std::make_exception_ptr(std::move(e))); | |||
} | |||
inline bool future_await_ready() | |||
{ | |||
//scoped_lock<lock_type> __guard(this->_mtx); | |||
return _has_value.load(std::memory_order_acquire); | |||
return _has_value.load(std::memory_order_acquire) != result_type::None; | |||
} | |||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | |||
void future_await_suspend(coroutine_handle<_PromiseT> handler); | |||
@@ -191,23 +189,89 @@ RESUMEF_NS | |||
public: | |||
~state_t() | |||
{ | |||
if (_has_value.load(std::memory_order_acquire)) | |||
cast_value_ptr()->~value_type(); | |||
switch (_has_value.load(std::memory_order_acquire)) | |||
{ | |||
case result_type::Value: | |||
_value.~value_type(); | |||
break; | |||
case result_type::Exception: | |||
_exception.~exception_ptr(); | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
auto future_await_resume() -> value_type; | |||
template<class _PromiseT, typename U, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | |||
void promise_yield_value(_PromiseT* promise, U&& val); | |||
void set_exception(std::exception_ptr e); | |||
template<typename U> | |||
void set_value(U&& val); | |||
template<class _Exp> | |||
inline void throw_exception(_Exp e) | |||
{ | |||
set_exception(std::make_exception_ptr(std::move(e))); | |||
} | |||
private: | |||
value_type * cast_value_ptr() | |||
union | |||
{ | |||
return static_cast<value_type*>(static_cast<void*>(_value)); | |||
std::exception_ptr _exception; | |||
value_type _value; | |||
}; | |||
template<typename U> | |||
void set_value_internal(U&& val); | |||
void set_exception_internal(std::exception_ptr e); | |||
}; | |||
template <typename _Ty> | |||
struct state_t<_Ty&> final : public state_future_t | |||
{ | |||
friend state_future_t; | |||
using state_future_t::lock_type; | |||
using value_type = _Ty; | |||
using reference_type = _Ty&; | |||
explicit state_t(size_t alloc_size) :state_future_t() | |||
{ | |||
_alloc_size = static_cast<uint32_t>(alloc_size); | |||
} | |||
explicit state_t(bool awaitor) :state_future_t(awaitor) | |||
{ | |||
_alloc_size = sizeof(*this); | |||
} | |||
public: | |||
~state_t() | |||
{ | |||
if (_has_value.load(std::memory_order_acquire) == result_type::Exception) | |||
_exception.~exception_ptr(); | |||
} | |||
auto future_await_resume()->reference_type; | |||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | |||
void promise_yield_value(_PromiseT* promise, reference_type val); | |||
alignas(value_type) unsigned char _value[sizeof(value_type)] = {0}; | |||
void set_exception(std::exception_ptr e); | |||
void set_value(reference_type val); | |||
template<class _Exp> | |||
inline void throw_exception(_Exp e) | |||
{ | |||
set_exception(std::make_exception_ptr(std::move(e))); | |||
} | |||
private: | |||
union | |||
{ | |||
std::exception_ptr _exception; | |||
value_type* _value; | |||
}; | |||
void set_value_internal(reference_type val); | |||
void set_exception_internal(std::exception_ptr e); | |||
}; | |||
template<> | |||
@@ -229,7 +293,16 @@ RESUMEF_NS | |||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | |||
void promise_yield_value(_PromiseT* promise); | |||
void set_exception(std::exception_ptr e); | |||
void set_value(); | |||
template<class _Exp> | |||
inline void throw_exception(_Exp e) | |||
{ | |||
set_exception(std::make_exception_ptr(std::move(e))); | |||
} | |||
private: | |||
std::exception_ptr _exception; | |||
}; | |||
} | |||
@@ -49,6 +49,8 @@ RESUMEF_NS | |||
sch->add_generator(this); | |||
} | |||
//------------------------------------------------------------------------------------------------ | |||
template<class _PromiseT, typename _Enable > | |||
void state_t<void>::promise_yield_value(_PromiseT* promise) | |||
{ | |||
@@ -62,7 +64,7 @@ RESUMEF_NS | |||
this->_coro = handler; | |||
} | |||
this->_has_value.store(true, std::memory_order_release); | |||
this->_has_value.store(result_type::Value, std::memory_order_release); | |||
if (!handler.done()) | |||
{ | |||
@@ -72,6 +74,8 @@ RESUMEF_NS | |||
} | |||
} | |||
//------------------------------------------------------------------------------------------------ | |||
template<typename _Ty> | |||
template<class _PromiseT, typename U, typename _Enable > | |||
void state_t<_Ty>::promise_yield_value(_PromiseT* promise, U&& val) | |||
@@ -86,15 +90,7 @@ RESUMEF_NS | |||
this->_coro = handler; | |||
} | |||
if (this->_has_value.load(std::memory_order_acquire)) | |||
{ | |||
*this->cast_value_ptr() = std::forward<U>(val); | |||
} | |||
else | |||
{ | |||
new (this->cast_value_ptr()) value_type(std::forward<U>(val)); | |||
this->_has_value.store(true, std::memory_order_release); | |||
} | |||
set_value_internal(std::forward<U>(val)); | |||
if (!handler.done()) | |||
{ | |||
@@ -108,12 +104,55 @@ RESUMEF_NS | |||
auto state_t<_Ty>::future_await_resume() -> value_type | |||
{ | |||
scoped_lock<lock_type> __guard(this->_mtx); | |||
if (this->_exception) | |||
switch (this->_has_value.load(std::memory_order_acquire)) | |||
{ | |||
case result_type::None: | |||
std::rethrow_exception(std::make_exception_ptr(future_exception{ error_code::not_ready })); | |||
break; | |||
case result_type::Exception: | |||
std::rethrow_exception(std::move(this->_exception)); | |||
if (!this->_has_value.load(std::memory_order_acquire)) | |||
std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready})); | |||
break; | |||
default: | |||
break; | |||
} | |||
return std::move(this->_value); | |||
} | |||
template<typename _Ty> | |||
template<typename U> | |||
void state_t<_Ty>::set_value_internal(U&& val) | |||
{ | |||
switch (_has_value.load(std::memory_order_acquire)) | |||
{ | |||
case result_type::Value: | |||
_value = std::forward<U>(val); | |||
break; | |||
case result_type::Exception: | |||
_exception.~exception_ptr(); | |||
default: | |||
new (&this->_value) value_type(std::forward<U>(val)); | |||
this->_has_value.store(result_type::Value, std::memory_order_release); | |||
break; | |||
} | |||
} | |||
return std::move(*this->cast_value_ptr()); | |||
template<typename _Ty> | |||
void state_t<_Ty>::set_exception_internal(std::exception_ptr e) | |||
{ | |||
switch (_has_value.load(std::memory_order_acquire)) | |||
{ | |||
case result_type::Exception: | |||
_exception = std::move(e); | |||
break; | |||
case result_type::Value: | |||
_value.~value_type(); | |||
default: | |||
new (&this->_exception) std::exception_ptr(std::move(e)); | |||
this->_has_value.store(result_type::Exception, std::memory_order_release); | |||
break; | |||
} | |||
} | |||
template<typename _Ty> | |||
@@ -121,16 +160,130 @@ RESUMEF_NS | |||
void state_t<_Ty>::set_value(U&& val) | |||
{ | |||
scoped_lock<lock_type> __guard(this->_mtx); | |||
set_value_internal(std::forward<U>(val)); | |||
scheduler_t* sch = this->get_scheduler(); | |||
if (sch != nullptr) | |||
{ | |||
if (this->has_handler_skip_lock()) | |||
sch->add_generator(this); | |||
else | |||
sch->del_final(this); | |||
} | |||
} | |||
template<typename _Ty> | |||
void state_t<_Ty>::set_exception(std::exception_ptr e) | |||
{ | |||
scoped_lock<lock_type> __guard(this->_mtx); | |||
set_exception_internal(std::move(e)); | |||
scheduler_t* sch = this->get_scheduler(); | |||
if (sch != nullptr) | |||
{ | |||
if (this->has_handler_skip_lock()) | |||
sch->add_generator(this); | |||
else | |||
sch->del_final(this); | |||
} | |||
} | |||
//------------------------------------------------------------------------------------------------ | |||
template<typename _Ty> | |||
template<class _PromiseT, typename _Enable > | |||
void state_t<_Ty&>::promise_yield_value(_PromiseT* promise, reference_type val) | |||
{ | |||
coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise); | |||
scoped_lock<lock_type> __guard(this->_mtx); | |||
if (!handler.done()) | |||
{ | |||
if (this->_coro == nullptr) | |||
this->_coro = handler; | |||
} | |||
set_value_internal(val); | |||
if (!handler.done()) | |||
{ | |||
scheduler_t* sch = this->get_scheduler(); | |||
if (sch != nullptr) | |||
sch->add_generator(this); | |||
} | |||
} | |||
template<typename _Ty> | |||
auto state_t<_Ty&>::future_await_resume() -> reference_type | |||
{ | |||
scoped_lock<lock_type> __guard(this->_mtx); | |||
switch (this->_has_value.load(std::memory_order_acquire)) | |||
{ | |||
case result_type::None: | |||
std::rethrow_exception(std::make_exception_ptr(future_exception{ error_code::not_ready })); | |||
break; | |||
case result_type::Exception: | |||
std::rethrow_exception(std::move(this->_exception)); | |||
break; | |||
default: | |||
break; | |||
} | |||
return static_cast<reference_type>(*this->_value); | |||
} | |||
if (this->_has_value.load(std::memory_order_acquire)) | |||
template<typename _Ty> | |||
void state_t<_Ty&>::set_value_internal(reference_type val) | |||
{ | |||
switch (_has_value.load(std::memory_order_acquire)) | |||
{ | |||
*this->cast_value_ptr() = std::forward<U>(val); | |||
case result_type::Exception: | |||
_exception.~exception_ptr(); | |||
default: | |||
this->_value = &val; | |||
this->_has_value.store(result_type::Value, std::memory_order_release); | |||
break; | |||
} | |||
else | |||
} | |||
template<typename _Ty> | |||
void state_t<_Ty&>::set_exception_internal(std::exception_ptr e) | |||
{ | |||
switch (_has_value.load(std::memory_order_acquire)) | |||
{ | |||
case result_type::Exception: | |||
_exception = std::move(e); | |||
break; | |||
default: | |||
new (&this->_exception) std::exception_ptr(std::move(e)); | |||
this->_has_value.store(result_type::Exception, std::memory_order_release); | |||
break; | |||
} | |||
} | |||
template<typename _Ty> | |||
void state_t<_Ty&>::set_value(reference_type val) | |||
{ | |||
scoped_lock<lock_type> __guard(this->_mtx); | |||
set_value_internal(val); | |||
scheduler_t* sch = this->get_scheduler(); | |||
if (sch != nullptr) | |||
{ | |||
new (this->cast_value_ptr()) value_type(std::forward<U>(val)); | |||
this->_has_value.store(true, std::memory_order_release); | |||
if (this->has_handler_skip_lock()) | |||
sch->add_generator(this); | |||
else | |||
sch->del_final(this); | |||
} | |||
} | |||
template<typename _Ty> | |||
void state_t<_Ty&>::set_exception(std::exception_ptr e) | |||
{ | |||
scoped_lock<lock_type> __guard(this->_mtx); | |||
set_exception_internal(std::move(e)); | |||
scheduler_t* sch = this->get_scheduler(); | |||
if (sch != nullptr) |
@@ -23,7 +23,7 @@ static void callback_get_long(int64_t val, _Ctype&& cb) | |||
//这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | |||
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) | |||
{ | |||
awaitable.set_value(val); | |||
@@ -60,13 +60,40 @@ static future_t<int64_t> loop_get_long(int64_t val) | |||
co_return val; | |||
} | |||
static future_t<std::string&> async_get_string(std::string & ref_string) | |||
{ | |||
awaitable_t<std::string&> awaitable; | |||
callback_get_long(std::stoi(ref_string), [awaitable, &ref_string](int64_t val) | |||
{ | |||
ref_string = std::to_string(val); | |||
awaitable.set_value(ref_string); | |||
}); | |||
return awaitable.get_future(); | |||
} | |||
static future_t<std::string&> resumable_get_string(std::string& val) | |||
{ | |||
std::cout << val << std::endl; | |||
val = co_await async_get_string(val); | |||
std::cout << val << std::endl; | |||
val = co_await async_get_string(val); | |||
std::cout << val << std::endl; | |||
val = co_await async_get_string(val); | |||
std::cout << val << std::endl; | |||
co_return static_cast<std::string&>(val); | |||
} | |||
void resumable_main_cb() | |||
{ | |||
//由于使用者可能不能明确的区分是resume function返回的awaitor还是awaitable function返回的awaitor | |||
//导致均有可能加入到协程里去调度。 | |||
//所以,协程调度器应该需要能处理这种情况。 | |||
go async_get_long(3); | |||
resumef::this_scheduler()->run_until_notask(); | |||
this_scheduler()->run_until_notask(); | |||
std::string ref_string{"2"}; | |||
go resumable_get_string(ref_string); | |||
this_scheduler()->run_until_notask(); | |||
GO | |||
{ | |||
@@ -75,5 +102,5 @@ void resumable_main_cb() | |||
}; | |||
go loop_get_long(3); | |||
resumef::this_scheduler()->run_until_notask(); | |||
this_scheduler()->run_until_notask(); | |||
} |
@@ -58,9 +58,9 @@ future_t<int64_t> resumeable_get_long(int64_t x, int64_t y) | |||
promise_type* promise = &handler.promise(); | |||
state_type* state = handler.promise().get_state(); | |||
std::cout << " future size=" << _Align_size<future_type>() << std::endl; | |||
std::cout << " promise size=" << _Align_size<promise_type>() << std::endl; | |||
std::cout << " state size=" << _Align_size<state_type>() << std::endl; | |||
std::cout << " future size=" << sizeof(future_type) << " / " << _Align_size<future_type>() << std::endl; | |||
std::cout << " promise size=" << sizeof(promise_type) << " / " << _Align_size<promise_type>() << std::endl; | |||
std::cout << " state size=" << sizeof(state_type) << " / "<< _Align_size<state_type>() << std::endl; | |||
std::cout << " frame size=" << _coro_frame_size() << ", alloc size=" << state->get_alloc_size() << std::endl; | |||
std::cout << " frame ptr=" << frame_ptr << "," << (void*)&frame_ptr << std::endl; | |||
@@ -97,9 +97,9 @@ future_t<> resumable_get_long_2(int64_t a, int64_t b, int64_t c) | |||
promise_type * promise = &handler.promise(); | |||
state_type * state = handler.promise().get_state(); | |||
std::cout << " future size=" << _Align_size<future_type>() << std::endl; | |||
std::cout << " promise size=" << _Align_size<promise_type>() << std::endl; | |||
std::cout << " state size=" << _Align_size<state_type>() << std::endl; | |||
std::cout << " future size=" << sizeof(future_type) << " / " << _Align_size<future_type>() << std::endl; | |||
std::cout << " promise size=" << sizeof(promise_type) << " / " << _Align_size<promise_type>() << std::endl; | |||
std::cout << " state size=" << sizeof(state_type) << " / "<< _Align_size<state_type>() << std::endl; | |||
std::cout << " frame size=" << _coro_frame_size() << ", alloc size=" << state->get_alloc_size() << std::endl; | |||
std::cout << " frame ptr=" << frame_ptr << ","<< (void*)&frame_ptr << std::endl; |
@@ -13,7 +13,7 @@ future_t<> test_sleep_use_timer() | |||
{ | |||
using namespace std::chrono; | |||
resumef::sleep_for(100ms); //incorrect!!! | |||
(void)resumef::sleep_for(100ms); //incorrect!!! | |||
co_await resumef::sleep_for(100ms); | |||
std::cout << "sleep_for 100ms." << std::endl; |
@@ -19,7 +19,7 @@ void run_in_thread(channel_t<bool>& c_done) | |||
local_scheduler my_scheduler; //产生本线程唯一的调度器 | |||
sch_in_thread = this_scheduler(); //本线程唯一的调度器赋值给sch_in_thread,以便于后续测试直接访问此线程的调度器 | |||
c_done << true; //数据都准备好了,通过channel通知其他协程可以启动后续依赖sch_in_thread变量的协程了 | |||
(void)c_done.write(true); //数据都准备好了,通过channel通知其他协程可以启动后续依赖sch_in_thread变量的协程了 | |||
//循环直到sch_in_thread为nullptr | |||
for (;;) | |||
@@ -71,7 +71,7 @@ static future_t<> resumable_get_long(int64_t val, channel_t<bool> & c_done) | |||
val = co_await async_get_long(val); | |||
std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl; | |||
c_done << true; | |||
(void)c_done.write(true); | |||
} | |||
void resumable_main_switch_scheduler() |
@@ -31,7 +31,7 @@ int main(int argc, const char* argv[]) | |||
{ | |||
(void)argc; | |||
(void)argv; | |||
//resumable_main_resumable(); | |||
//resumable_main_layout(); | |||
//return 0; | |||
//if (argc > 1) | |||
@@ -61,7 +61,9 @@ int main(int argc, const char* argv[]) | |||
resumable_main_switch_scheduler(); | |||
std::cout << "ALL OK!" << std::endl; | |||
#if !defined(__clang__) || defined(_WIN64) | |||
benchmark_main_channel_passing_next(); //这是一个死循环测试 | |||
#endif | |||
return 0; | |||
} |
@@ -34,19 +34,19 @@ | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> | |||
<ConfigurationType>Application</ConfigurationType> | |||
<UseDebugLibraries>false</UseDebugLibraries> | |||
<PlatformToolset>v142</PlatformToolset> | |||
<PlatformToolset>ClangCL</PlatformToolset> | |||
<WholeProgramOptimization>true</WholeProgramOptimization> | |||
<CharacterSet>NotSet</CharacterSet> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> | |||
<ConfigurationType>Application</ConfigurationType> | |||
<PlatformToolset>v142</PlatformToolset> | |||
<PlatformToolset>ClangCL</PlatformToolset> | |||
<UseDebugLibraries>true</UseDebugLibraries> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | |||
<ConfigurationType>Application</ConfigurationType> | |||
<UseDebugLibraries>false</UseDebugLibraries> | |||
<PlatformToolset>v142</PlatformToolset> | |||
<PlatformToolset>ClangCL</PlatformToolset> | |||
<WholeProgramOptimization>true</WholeProgramOptimization> | |||
<CharacterSet>NotSet</CharacterSet> | |||
</PropertyGroup> | |||
@@ -74,9 +74,7 @@ | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||
<LinkIncremental>true</LinkIncremental> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |||
<LinkIncremental>false</LinkIncremental> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" /> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet> | |||
<EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis> | |||
@@ -110,7 +108,6 @@ | |||
<CLanguageStandard>c11</CLanguageStandard> | |||
<CppLanguageStandard>c++1y</CppLanguageStandard> | |||
<DisableSpecificWarnings>4834</DisableSpecificWarnings> | |||
<TreatWarningAsError>true</TreatWarningAsError> | |||
</ClCompile> | |||
<Link> | |||
<SubSystem>Console</SubSystem> | |||
@@ -131,7 +128,9 @@ | |||
<LanguageStandard>stdcpplatest</LanguageStandard> | |||
<StringPooling>true</StringPooling> | |||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed> | |||
<OmitFramePointers /> | |||
<OmitFramePointers>true</OmitFramePointers> | |||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> | |||
<BufferSecurityCheck>false</BufferSecurityCheck> | |||
</ClCompile> | |||
<Link> | |||
<SubSystem>Console</SubSystem> | |||
@@ -150,7 +149,6 @@ | |||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;ASIO_STANDALONE;RESUMEF_ENABLE_MULT_SCHEDULER=1;_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING=1;ASIO_DISABLE_CONCEPTS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||
<AdditionalIncludeDirectories>..\librf;..\..\asio\asio\include;..\..\asio-1.10.6\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | |||
<AdditionalOptions>/await</AdditionalOptions> | |||
<ExceptionHandling>Sync</ExceptionHandling> | |||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed> | |||
<StringPooling>true</StringPooling> | |||
<LanguageStandard>stdcpplatest</LanguageStandard> | |||
@@ -163,7 +161,6 @@ | |||
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations> | |||
<BufferSecurityCheck>false</BufferSecurityCheck> | |||
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration> | |||
<TreatWarningAsError>true</TreatWarningAsError> | |||
</ClCompile> | |||
<Link> | |||
<SubSystem>Console</SubSystem> | |||
@@ -176,9 +173,13 @@ | |||
</Link> | |||
</ItemDefinitionGroup> | |||
<ItemGroup> | |||
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp" /> | |||
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp"> | |||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> | |||
</ClCompile> | |||
<ClCompile Include="..\benchmark\benchmark_async_mem.cpp" /> | |||
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp" /> | |||
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp"> | |||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> | |||
</ClCompile> | |||
<ClCompile Include="..\librf\src\event.cpp" /> | |||
<ClCompile Include="..\librf\src\mutex.cpp" /> | |||
<ClCompile Include="..\librf\src\rf_task.cpp" /> |