namespace resumef | namespace resumef | ||||
{ | { | ||||
template<class _Ty> | template<class _Ty> | ||||
struct awaitable_t | |||||
struct awaitable_impl_t | |||||
{ | { | ||||
using value_type = _Ty; | using value_type = _Ty; | ||||
using state_type = state_t<value_type>; | using state_type = state_t<value_type>; | ||||
using future_type = future_t<value_type>; | using future_type = future_t<value_type>; | ||||
using lock_type = typename state_type::lock_type; | using lock_type = typename state_type::lock_type; | ||||
private: | |||||
mutable counted_ptr<state_type> _state = make_counted<state_type>(true); | |||||
public: | |||||
awaitable_t() {} | |||||
awaitable_t(const awaitable_t&) = default; | |||||
awaitable_t(awaitable_t&&) = default; | |||||
awaitable_impl_t() {} | |||||
awaitable_impl_t(const awaitable_impl_t&) = default; | |||||
awaitable_impl_t(awaitable_impl_t&&) = default; | |||||
awaitable_t& operator = (const awaitable_t&) = default; | |||||
awaitable_t& operator = (awaitable_t&&) = default; | |||||
awaitable_impl_t& operator = (const awaitable_impl_t&) = default; | |||||
awaitable_impl_t& operator = (awaitable_impl_t&&) = default; | |||||
void set_value(value_type value) const | |||||
void set_exception(std::exception_ptr e) const | |||||
{ | { | ||||
_state->set_value(std::move(value)); | |||||
_state->set_exception(std::move(e)); | |||||
_state = nullptr; | _state = nullptr; | ||||
} | } | ||||
void set_exception(std::exception_ptr e) | |||||
template<class _Exp> | |||||
void throw_exception(_Exp e) const | |||||
{ | { | ||||
_state->set_exception(std::move(e)); | |||||
_state = nullptr; | |||||
set_exception(std::make_exception_ptr(std::move(e))); | |||||
} | } | ||||
future_type get_future() | future_type get_future() | ||||
{ | { | ||||
return future_type{ _state }; | return future_type{ _state }; | ||||
} | } | ||||
protected: | |||||
mutable counted_ptr<state_type> _state = make_counted<state_type>(true); | |||||
}; | }; | ||||
template<> | |||||
struct awaitable_t<void> | |||||
template<class _Ty> | |||||
struct awaitable_t : public awaitable_impl_t<_Ty> | |||||
{ | { | ||||
using value_type = void; | |||||
using state_type = state_t<void>; | |||||
using future_type = future_t<void>; | |||||
using lock_type = typename state_type::lock_type; | |||||
mutable counted_ptr<state_type> _state = make_counted<state_type>(true); | |||||
using awaitable_impl_t::awaitable_impl_t; | |||||
awaitable_t() {} | |||||
awaitable_t(const awaitable_t&) = default; | |||||
awaitable_t(awaitable_t&&) = default; | |||||
awaitable_t& operator = (const awaitable_t&) = default; | |||||
awaitable_t& operator = (awaitable_t&&) = default; | |||||
void set_value() const | |||||
void set_value(value_type value) const | |||||
{ | { | ||||
_state->set_value(); | |||||
_state->set_value(std::move(value)); | |||||
_state = nullptr; | _state = nullptr; | ||||
} | } | ||||
}; | |||||
void set_exception(std::exception_ptr e) | |||||
{ | |||||
_state->set_exception(std::move(e)); | |||||
_state = nullptr; | |||||
} | |||||
template<> | |||||
struct awaitable_t<void> : public awaitable_impl_t<void> | |||||
{ | |||||
using awaitable_impl_t::awaitable_impl_t; | |||||
future_type get_future() | |||||
void set_value() const | |||||
{ | { | ||||
return future_type{ _state }; | |||||
_state->set_value(); | |||||
_state = nullptr; | |||||
} | } | ||||
}; | }; | ||||
} | } |
template<class _Ty = void> | template<class _Ty = void> | ||||
struct future_t; | struct future_t; | ||||
using future_vt = future_t<>; | |||||
using future_vt [[deprecated]] = future_t<>; | |||||
template<class _Ty = void> | template<class _Ty = void> | ||||
struct promise_t; | struct promise_t; |
#include "scheduler.h" | #include "scheduler.h" | ||||
#include "awaitable.h" | |||||
#include "sleep.h" | #include "sleep.h" | ||||
namespace resumef | namespace resumef | ||||
{ | { | ||||
future_t<> sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler_t& scheduler_) | future_t<> sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler_t& scheduler_) | ||||
{ | { | ||||
promise_vt awaitable; | |||||
awaitable_t<> awaitable; | |||||
(void)scheduler_.timer()->add(tp_, | (void)scheduler_.timer()->add(tp_, | ||||
[st = awaitable._state](bool cancellation_requested) | |||||
[awaitable](bool cancellation_requested) | |||||
{ | { | ||||
if (cancellation_requested) | if (cancellation_requested) | ||||
st->throw_exception(timer_canceled_exception{ error_code::timer_canceled }); | |||||
awaitable.throw_exception(timer_canceled_exception{ error_code::timer_canceled }); | |||||
else | else | ||||
st->set_value(); | |||||
awaitable.set_value(); | |||||
}); | }); | ||||
return awaitable.get_future(); | return awaitable.get_future(); |
using namespace std::chrono; | using namespace std::chrono; | ||||
std::thread([val, cb = std::forward<_Ctype>(cb)] | std::thread([val, cb = std::forward<_Ctype>(cb)] | ||||
{ | { | ||||
//std::this_thread::sleep_for(500ms); | |||||
std::this_thread::sleep_for(2s); | |||||
std::this_thread::sleep_for(500ms); | |||||
cb(val * val); | cb(val * val); | ||||
}).detach(); | }).detach(); | ||||
} | } |
//请打开结构化异常(/EHa) | //请打开结构化异常(/EHa) | ||||
auto async_signal_exception(const intptr_t dividend) | auto async_signal_exception(const intptr_t dividend) | ||||
{ | { | ||||
promise_t<int64_t> awaitable; | |||||
awaitable_t<int64_t> awaitable; | |||||
std::thread([dividend, st = awaitable._state] | |||||
std::thread([dividend, awaitable] | |||||
{ | { | ||||
std::this_thread::sleep_for(std::chrono::milliseconds(50)); | std::this_thread::sleep_for(std::chrono::milliseconds(50)); | ||||
try | try | ||||
//也可以注释掉这个判断,使用结构化异常。但就获得不了具体描述信息了 | //也可以注释掉这个判断,使用结构化异常。但就获得不了具体描述信息了 | ||||
if (dividend == 0) | if (dividend == 0) | ||||
throw std::logic_error("divided by zero"); | throw std::logic_error("divided by zero"); | ||||
st->set_value(10000 / dividend); | |||||
awaitable.set_value(10000 / dividend); | |||||
} | } | ||||
catch (...) | catch (...) | ||||
{ | { | ||||
st->set_exception(std::current_exception()); | |||||
awaitable.set_exception(std::current_exception()); | |||||
} | } | ||||
}).detach(); | }).detach(); | ||||
auto async_signal_exception2(const intptr_t dividend) | auto async_signal_exception2(const intptr_t dividend) | ||||
{ | { | ||||
promise_t<int64_t> awaitable; | |||||
awaitable_t<int64_t> awaitable; | |||||
std::thread([dividend, st = awaitable._state] | |||||
std::thread([dividend, awaitable] | |||||
{ | { | ||||
std::this_thread::sleep_for(std::chrono::milliseconds(50)); | std::this_thread::sleep_for(std::chrono::milliseconds(50)); | ||||
if (dividend == 0) | if (dividend == 0) | ||||
st->throw_exception(std::logic_error("divided by zero")); | |||||
awaitable.throw_exception(std::logic_error("divided by zero")); | |||||
else | else | ||||
st->set_value(10000 / dividend); | |||||
awaitable.set_value(10000 / dividend); | |||||
}).detach(); | }).detach(); | ||||
return awaitable.get_future(); | return awaitable.get_future(); |
return awaitable.get_future(); | return awaitable.get_future(); | ||||
} | } | ||||
future_vt heavy_computing_sequential(int64_t val) | |||||
future_t<> heavy_computing_sequential(int64_t val) | |||||
{ | { | ||||
for(size_t i = 0; i < 3; ++i) | for(size_t i = 0; i < 3; ++i) | ||||
{ | { |
mutex_t g_lock; | mutex_t g_lock; | ||||
std::deque<size_t> g_queue; | std::deque<size_t> g_queue; | ||||
future_vt test_mutex_pop(size_t idx) | |||||
future_t<> test_mutex_pop(size_t idx) | |||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
} | } | ||||
} | } | ||||
future_vt test_mutex_push() | |||||
future_t<> test_mutex_push() | |||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
using namespace resumef; | using namespace resumef; | ||||
future_vt test_routine_use_timer() | |||||
future_t<> test_routine_use_timer() | |||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
std::cout << "test_routine_use_timer" << std::endl; | std::cout << "test_routine_use_timer" << std::endl; | ||||
} | } | ||||
} | } | ||||
future_vt test_routine_use_timer_2() | |||||
future_t<> test_routine_use_timer_2() | |||||
{ | { | ||||
std::cout << "test_routine_use_timer_2" << std::endl; | std::cout << "test_routine_use_timer_2" << std::endl; | ||||
using namespace resumef; | using namespace resumef; | ||||
future_vt test_sleep_use_timer() | |||||
future_t<> test_sleep_use_timer() | |||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
event_t evts[8]; | event_t evts[8]; | ||||
go[&]() -> future_vt | |||||
go[&]() -> future_t<> | |||||
{ | { | ||||
if (co_await event_t::wait_all(evts)) | if (co_await event_t::wait_all(evts)) | ||||
std::cout << "all event signal!" << std::endl; | std::cout << "all event signal!" << std::endl; | ||||
srand((int)time(nullptr)); | srand((int)time(nullptr)); | ||||
for (size_t i = 0; i < _countof(evts); ++i) | for (size_t i = 0; i < _countof(evts); ++i) | ||||
{ | { | ||||
go[&, i]() -> future_vt | |||||
go[&, i]() -> future_t<> | |||||
{ | { | ||||
co_await resumef::sleep_for(1ms * (500 + rand() % 1000)); | co_await resumef::sleep_for(1ms * (500 + rand() % 1000)); | ||||
evts[i].signal(); | evts[i].signal(); |
using namespace resumef; | using namespace resumef; | ||||
template<size_t _N> | |||||
future_vt test_loop_sleep() | |||||
future_t<> test_loop_sleep(size_t _N, char * ch) | |||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
for (size_t i = 0; i < _N; ++i) | for (size_t i = 0; i < _N; ++i) | ||||
{ | { | ||||
co_await resumef::sleep_for(100ms); | co_await resumef::sleep_for(100ms); | ||||
std::cout << "."; | |||||
std::cout << ch; | |||||
} | } | ||||
std::cout << std::endl; | std::cout << std::endl; | ||||
} | } | ||||
future_vt test_recursive_await() | |||||
future_t<> test_recursive_await() | |||||
{ | { | ||||
std::cout << "---1" << std::endl; | |||||
co_await test_loop_sleep<5>(); | |||||
std::cout << "A:---1" << std::endl; | |||||
co_await test_loop_sleep(5, "="); | |||||
std::cout << "---2" << std::endl; | |||||
co_await test_loop_sleep<6>(); | |||||
std::cout << "A:---2" << std::endl; | |||||
co_await test_loop_sleep(6, "="); | |||||
std::cout << "---3" << std::endl; | |||||
co_await test_loop_sleep<7>(); | |||||
std::cout << "A:---3" << std::endl; | |||||
co_await test_loop_sleep(7, "="); | |||||
std::cout << "---4" << std::endl; | |||||
std::cout << "A:---4" << std::endl; | |||||
} | } | ||||
future_vt test_recursive_go() | |||||
future_t<> test_recursive_go() | |||||
{ | { | ||||
std::cout << "---1" << std::endl; | |||||
co_await test_loop_sleep<3>(); | |||||
std::cout << "B:---1" << std::endl; | |||||
co_await test_loop_sleep(3, "+"); | |||||
std::cout << "---2" << std::endl; | |||||
go test_loop_sleep<5>(); | |||||
std::cout << "B:---2" << std::endl; | |||||
go test_loop_sleep(8, "*"); | |||||
std::cout << "---3" << std::endl; | |||||
co_await test_loop_sleep<4>(); | |||||
std::cout << "B:---3" << std::endl; | |||||
co_await test_loop_sleep(4, "+"); | |||||
std::cout << "---4" << std::endl; | |||||
std::cout << "B:---4" << std::endl; | |||||
} | } | ||||
void resumable_main_suspend_always() | void resumable_main_suspend_always() |
return dt; | return dt; | ||||
}(), | }(), | ||||
[]() ->future_vt | |||||
[]() ->future_t<> | |||||
{ | { | ||||
auto dt = rand() % 1000; | auto dt = rand() % 1000; | ||||
co_await sleep_for(1ms * dt); | co_await sleep_for(1ms * dt); | ||||
std::cout << dt << "@b" << std::endl; | std::cout << dt << "@b" << std::endl; | ||||
}(), | }(), | ||||
[]() ->future_vt | |||||
[]() ->future_t<> | |||||
{ | { | ||||
auto dt = rand() % 1000; | auto dt = rand() % 1000; | ||||
co_await sleep_for(1ms * dt); | co_await sleep_for(1ms * dt); | ||||
return dt; | return dt; | ||||
}; | }; | ||||
auto my_sleep_v = [](const char * name) -> future_vt | |||||
auto my_sleep_v = [](const char * name) -> future_t<> | |||||
{ | { | ||||
auto dt = rand() % 1000; | auto dt = rand() % 1000; | ||||
co_await sleep_for(1ms * dt); | co_await sleep_for(1ms * dt); |
int main(int argc, const char* argv[]) | int main(int argc, const char* argv[]) | ||||
{ | { | ||||
resumable_main_cb(); | resumable_main_cb(); | ||||
resumable_main_suspend_always(); | |||||
//resumable_main_exception(); | |||||
/* | /* | ||||
resumable_main_resumable(); | resumable_main_resumable(); | ||||
resumable_main_multi_thread(); | resumable_main_multi_thread(); | ||||
resumable_main_yield_return(); | resumable_main_yield_return(); | ||||
resumable_main_timer(); | resumable_main_timer(); | ||||
resumable_main_suspend_always(); | |||||
resumable_main_sleep(); | resumable_main_sleep(); | ||||
resumable_main_routine(); | resumable_main_routine(); | ||||
resumable_main_resumable(); | resumable_main_resumable(); | ||||
resumable_main_dynamic_go(); | resumable_main_dynamic_go(); | ||||
resumable_main_channel(); | resumable_main_channel(); | ||||
resumable_main_cb(); | resumable_main_cb(); | ||||
resumable_main_exception(); | |||||
*/ | */ | ||||
return 0; | return 0; |
</ClCompile> | </ClCompile> | ||||
<ClCompile Include="..\librf\src\rf_task.cpp" /> | <ClCompile Include="..\librf\src\rf_task.cpp" /> | ||||
<ClCompile Include="..\librf\src\scheduler.cpp" /> | <ClCompile Include="..\librf\src\scheduler.cpp" /> | ||||
<ClCompile Include="..\librf\src\sleep.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<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="..\librf\src\when.cpp"> | ||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | ||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | ||||
</ClCompile> | </ClCompile> | ||||
<ClCompile Include="..\tutorial\test_async_exception.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_exception.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_modern_cb.cpp"> | <ClCompile Include="..\tutorial\test_async_modern_cb.cpp"> | ||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | ||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | ||||
</ClCompile> | </ClCompile> | ||||
<ClCompile Include="..\tutorial\test_async_sleep.cpp"> | <ClCompile Include="..\tutorial\test_async_sleep.cpp"> | ||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | ||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | ||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | </ClCompile> | ||||
<ClCompile Include="..\tutorial\test_async_suspend_always.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_suspend_always.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_timer.cpp"> | <ClCompile Include="..\tutorial\test_async_timer.cpp"> | ||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | ||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> |
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</ClInclude> | </ClInclude> | ||||
<ClInclude Include="..\librf\src\awaitable.h"> | <ClInclude Include="..\librf\src\awaitable.h"> | ||||
<Filter>librf</Filter> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | </ClInclude> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> |