@@ -12,7 +12,7 @@ librf是一个基于C++ Coroutines提案 ‘Stackless Resumable Functions’编 | |||
librf有以下特点: | |||
* 1.基于C++17提案'Stackless Resumable Functions'编写的非对称stackless协程库,可以以同步的方式编写简单的代码,同时获得异步的性能 | |||
* 2.理论上支持海量协程, 创建100万个协程只需使用<820M>物理内存 | |||
* 2.理论上支持海量协程, 创建100万个协程只需使用<430M>物理内存 | |||
* 3.提供协程锁(mutex), 定时器, channel等特性, 帮助用户更加容易地编写程序 | |||
* 4.可以很好的跟asio,libuv等库结合,能跟现有的callback范式的异步/延迟代码很好的结合 | |||
* 5.目前还处于实验状态,不对今后正式的C++ Coroutines支持有任何正式的承诺 |
@@ -71,6 +71,7 @@ namespace resumef | |||
already_acquired, // attempt to get another future | |||
unlock_more, // unlock 次数多余lock次数 | |||
read_before_write, // 0容量的channel,先读后写 | |||
timer_canceled, // 定时器被意外取消 | |||
max__ | |||
}; | |||
@@ -108,6 +109,16 @@ namespace resumef | |||
} | |||
}; | |||
struct timer_canceled_exception : public std::exception | |||
{ | |||
error_code _error; | |||
timer_canceled_exception(error_code fe) | |||
: exception(get_error_string(fe, "timer canceled")) | |||
, _error(fe) | |||
{ | |||
} | |||
}; | |||
struct scheduler; | |||
struct state_base; | |||
@@ -18,6 +18,7 @@ namespace resumef | |||
"already_acquired", | |||
"unlock_more", | |||
"read_before_write", | |||
"timer_canceled", | |||
}; | |||
static char sz_future_error_buffer[256]; |
@@ -4,15 +4,17 @@ | |||
namespace resumef | |||
{ | |||
future_t<bool> sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler & scheduler_) | |||
future_vt sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler & scheduler_) | |||
{ | |||
promise_t<bool> awaitable; | |||
promise_vt awaitable; | |||
scheduler_.timer()->add(tp_, | |||
[st = awaitable._state](bool cancellation_requested) | |||
{ | |||
st->set_value(cancellation_requested); | |||
if (cancellation_requested) | |||
st->throw_exception(timer_canceled_exception{ error_code::timer_canceled }); | |||
else | |||
st->set_value(); | |||
}); | |||
return awaitable.get_future(); |
@@ -1,34 +1,38 @@ | |||
//协程的定时器 | |||
//如果定时器被取消了,则会抛 timer_canceled_exception 异常 | |||
//不使用co_await而单独sleep_for/sleep_until,是错误的用法,并不能达到等待的目的。而仅仅是添加了一个无效的定时器,造成无必要的内存使用 | |||
// | |||
#pragma once | |||
namespace resumef | |||
{ | |||
struct scheduler; | |||
RF_API future_t<bool> sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler & scheduler_); | |||
RF_API future_vt sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler & scheduler_); | |||
inline future_t<bool> sleep_for_(const std::chrono::system_clock::duration& dt_, scheduler & scheduler_) | |||
inline future_vt sleep_for_(const std::chrono::system_clock::duration& dt_, scheduler & scheduler_) | |||
{ | |||
return std::move(sleep_until_(std::chrono::system_clock::now() + dt_, scheduler_)); | |||
} | |||
template<class _Rep, class _Period> | |||
future_t<bool> sleep_for(const std::chrono::duration<_Rep, _Period>& dt_, scheduler & scheduler_) | |||
future_vt 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_)); | |||
} | |||
template<class _Rep, class _Period> | |||
future_t<bool> sleep_for(const std::chrono::duration<_Rep, _Period>& dt_) | |||
future_vt 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())); | |||
} | |||
template<class _Clock, class _Duration = typename _Clock::duration> | |||
future_t<bool> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_, scheduler & scheduler_) | |||
future_vt 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_)); | |||
} | |||
template<class _Clock, class _Duration> | |||
future_t<bool> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_) | |||
future_vt 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())); | |||
} |
@@ -47,39 +47,39 @@ namespace resumef | |||
#endif | |||
} | |||
void state_base::set_value_none_lock() | |||
{ | |||
// Set all members first as calling coroutine may reset stuff here. | |||
_ready = true; | |||
if (_coro) | |||
{ | |||
void state_base::set_value_none_lock() | |||
{ | |||
// Set all members first as calling coroutine may reset stuff here. | |||
_ready = true; | |||
if (_coro) | |||
{ | |||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||
auto sch_ = this->current_scheduler(); | |||
#else | |||
auto sch_ = this_scheduler(); | |||
#endif | |||
if(sch_) sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||
} | |||
} | |||
auto sch_ = this->current_scheduler(); | |||
#else | |||
auto sch_ = this_scheduler(); | |||
#endif | |||
if(sch_) sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||
} | |||
} | |||
void state_base::set_exception(std::exception_ptr && e_) | |||
{ | |||
scoped_lock<lock_type> __guard(_mtx); | |||
_exception = std::move(e_); | |||
// Set all members first as calling coroutine may reset stuff here. | |||
_ready = true; | |||
if (_coro) | |||
{ | |||
// Set all members first as calling coroutine may reset stuff here. | |||
_ready = true; | |||
if (_coro) | |||
{ | |||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||
auto sch_ = this->current_scheduler(); | |||
auto sch_ = this->current_scheduler(); | |||
#else | |||
auto sch_ = this_scheduler(); | |||
auto sch_ = this_scheduler(); | |||
#endif | |||
if (sch_) sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||
} | |||
if (sch_) sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||
} | |||
} | |||
void state_base::await_suspend(coroutine_handle<> resume_cb) |
@@ -35,7 +35,7 @@ namespace resumef | |||
std::atomic<bool> _done = false; | |||
public: | |||
state_base() | |||
state_base() noexcept | |||
{ | |||
#if RESUMEF_DEBUG_COUNTER | |||
++g_resumef_state_count; | |||
@@ -190,7 +190,16 @@ namespace resumef | |||
_value = std::forward<value_type>(t); | |||
state_base::set_value_none_lock(); | |||
} | |||
_Ty & get_value() | |||
value_type & set_value__() | |||
{ | |||
scoped_lock<lock_type> __guard(_mtx); | |||
state_base::set_value_none_lock(); | |||
return _value; | |||
} | |||
value_type & get_value() | |||
{ | |||
scoped_lock<lock_type> __guard(_mtx); | |||
@@ -198,6 +207,7 @@ namespace resumef | |||
throw future_exception{ error_code::not_ready }; | |||
return _value; | |||
} | |||
void reset() | |||
{ | |||
scoped_lock<lock_type> __guard(_mtx); |
@@ -13,13 +13,20 @@ future_vt test_sleep_use_timer() | |||
{ | |||
using namespace std::chrono; | |||
resumef::sleep_for(100ms); //incorrect!!! | |||
co_await resumef::sleep_for(100ms); | |||
std::cout << "timer after 100ms." << std::endl; | |||
if (co_await resumef::sleep_until(system_clock::now() + 200ms)) | |||
std::cout << "timer canceled." << std::endl; | |||
else | |||
try | |||
{ | |||
co_await resumef::sleep_until(system_clock::now() + 200ms); | |||
std::cout << "timer after 200ms." << std::endl; | |||
} | |||
catch (resumef::timer_canceled_exception) | |||
{ | |||
std::cout << "timer canceled." << std::endl; | |||
} | |||
} | |||
void test_wait_all_events_with_signal_by_sleep() | |||
@@ -37,7 +44,7 @@ void test_wait_all_events_with_signal_by_sleep() | |||
}; | |||
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 | |||
{ |
@@ -22,7 +22,9 @@ extern void resumable_main_benchmark_mem(); | |||
int main(int argc, const char * argv[]) | |||
{ | |||
resumable_main_sleep(); | |||
//resumable_main_resumable(); | |||
/* | |||
resumable_main_when_all(); | |||
resumable_main_multi_thread(); | |||
resumable_main_yield_return(); | |||
@@ -38,6 +40,7 @@ int main(int argc, const char * argv[]) | |||
resumable_main_channel(); | |||
resumable_main_cb(); | |||
resumable_main_exception(); | |||
*/ | |||
return 0; | |||
} |