bool await_ready() | bool await_ready() | ||||
{ | { | ||||
return _state->_ready; | |||||
return _state->ready(); | |||||
} | } | ||||
void await_suspend(coroutine_handle<> resume_cb) | void await_suspend(coroutine_handle<> resume_cb) | ||||
{ | { | ||||
//if ready, can get value | //if ready, can get value | ||||
bool ready() | bool ready() | ||||
{ | { | ||||
return _state->_ready; | |||||
return _state->ready(); | |||||
} | } | ||||
auto & get_value() | auto & get_value() | ||||
{ | { | ||||
bool await_ready() | bool await_ready() | ||||
{ | { | ||||
return _state->_ready; | |||||
return _state->ready(); | |||||
} | } | ||||
void await_suspend(coroutine_handle<> resume_cb) | void await_suspend(coroutine_handle<> resume_cb) | ||||
{ | { |
{ | { | ||||
auto * _state = _future._state.get(); | auto * _state = _future._state.get(); | ||||
_state->resume(); | _state->resume(); | ||||
return !_state->ready() && !_state->_done; | |||||
return !_state->ready() && !_state->done(); | |||||
} | } | ||||
virtual void cancel() override | virtual void cancel() override | ||||
{ | { |
{ | { | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | #if RESUMEF_ENABLE_MULT_SCHEDULER | ||||
auto sch_ = this->current_scheduler(); | auto sch_ = this->current_scheduler(); | ||||
if (sch_ == nullptr) | |||||
sch_ = this_scheduler(); | |||||
#else | #else | ||||
auto sch_ = this_scheduler(); | auto sch_ = this_scheduler(); | ||||
#endif | #endif | ||||
sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||||
if(sch_) sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||||
} | } | ||||
} | } | ||||
{ | { | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | #if RESUMEF_ENABLE_MULT_SCHEDULER | ||||
auto sch_ = this->current_scheduler(); | auto sch_ = this->current_scheduler(); | ||||
if (sch_ == nullptr) | |||||
sch_ = this_scheduler(); | |||||
#else | #else | ||||
auto sch_ = this_scheduler(); | auto sch_ = this_scheduler(); | ||||
#endif | #endif | ||||
sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||||
if (sch_) sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||||
} | } | ||||
} | } | ||||
RF_API void set_value_none_lock(); | RF_API void set_value_none_lock(); | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | #if RESUMEF_ENABLE_MULT_SCHEDULER | ||||
private: | private: | ||||
void * _this_promise = nullptr; | |||||
std::atomic<void *> _this_promise = nullptr; | |||||
scheduler * _current_scheduler = nullptr; | scheduler * _current_scheduler = nullptr; | ||||
std::vector<counted_ptr<state_base>> _depend_states; | std::vector<counted_ptr<state_base>> _depend_states; | ||||
#endif | #endif | ||||
public: | |||||
protected: | |||||
coroutine_handle<> _coro; | coroutine_handle<> _coro; | ||||
std::atomic<intptr_t> _count = 0; // tracks reference count of state object | std::atomic<intptr_t> _count = 0; // tracks reference count of state object | ||||
std::exception_ptr _exception; | std::exception_ptr _exception; | ||||
bool _ready = false; | |||||
bool _cancellation = false; | |||||
bool _done = false; | |||||
std::atomic<bool> _ready = false; | |||||
std::atomic<bool> _cancellation = false; | |||||
std::atomic<bool> _done = false; | |||||
public: | |||||
state_base() | state_base() | ||||
{ | { | ||||
#if RESUMEF_DEBUG_COUNTER | #if RESUMEF_DEBUG_COUNTER | ||||
{ | { | ||||
return _ready; | return _ready; | ||||
} | } | ||||
bool done() const | |||||
{ | |||||
return _done; | |||||
} | |||||
void reset_none_lock() | void reset_none_lock() | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(_mtx); | |||||
_coro = nullptr; | _coro = nullptr; | ||||
_ready = false; | _ready = false; | ||||
} | } | ||||
} | } | ||||
void resume() | void resume() | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(_mtx); | |||||
if (_coro) | if (_coro) | ||||
{ | { | ||||
#if RESUMEF_DEBUG_COUNTER | #if RESUMEF_DEBUG_COUNTER | ||||
#endif | #endif | ||||
auto coro = _coro; | auto coro = _coro; | ||||
_coro = nullptr; | _coro = nullptr; | ||||
coro(); | coro(); | ||||
} | } | ||||
} | } | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | #if RESUMEF_ENABLE_MULT_SCHEDULER | ||||
promise_t<void> * parent_promise() const; | promise_t<void> * parent_promise() const; | ||||
//scheduler * parent_scheduler() const; | |||||
scheduler * parent_scheduler() const; | |||||
void * this_promise() const | void * this_promise() const | ||||
{ | { | ||||
void await_suspend(coroutine_handle<> resume_cb); | void await_suspend(coroutine_handle<> resume_cb); | ||||
void final_suspend() | void final_suspend() | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(_mtx); | |||||
_done = true; | _done = true; | ||||
} | } | ||||
//以上是通过future_t/promise_t, 与编译器生成的resumable function交互的接口 | //以上是通过future_t/promise_t, 与编译器生成的resumable function交互的接口 | ||||
_value = value_type{}; | _value = value_type{}; | ||||
} | } | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
promise_t<_Ty> * parent_promise() const | promise_t<_Ty> * parent_promise() const | ||||
{ | { | ||||
return reinterpret_cast<promise_t<_Ty> *>(state_base::parent_promise()); | return reinterpret_cast<promise_t<_Ty> *>(state_base::parent_promise()); | ||||
} | } | ||||
#endif | |||||
}; | }; | ||||
template<> | template<> |
using namespace std::chrono; | using namespace std::chrono; | ||||
static std::mutex cout_mutex; | static std::mutex cout_mutex; | ||||
std::atomic<intptr_t> gcounter = 0; | |||||
#define OUTPUT_DEBUG 0 | #define OUTPUT_DEBUG 0 | ||||
try | try | ||||
{ | { | ||||
auto val = co_await c.read(); | auto val = co_await c.read(); | ||||
++gcounter; | |||||
#if OUTPUT_DEBUG | #if OUTPUT_DEBUG | ||||
{ | { | ||||
scoped_lock<std::mutex> __lock(cout_mutex); | scoped_lock<std::mutex> __lock(cout_mutex); | ||||
std::thread write_th([&] | std::thread write_th([&] | ||||
{ | { | ||||
//local_scheduler my_scheduler; //2017/11/27日,仍然存在BUG。真多线程下调度,存在有协程无法被调度完成的BUG | |||||
local_scheduler my_scheduler; //2017/12/14日,仍然存在BUG。真多线程下调度,存在有协程无法被调度完成的BUG | |||||
go test_channel_producer(c, BATCH * N); | go test_channel_producer(c, BATCH * N); | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); | ||||
#endif | |||||
std::cout << "Write OK\r\n"; | std::cout << "Write OK\r\n"; | ||||
}); | }); | ||||
{ | { | ||||
read_th[i] = std::thread([&] | read_th[i] = std::thread([&] | ||||
{ | { | ||||
//local_scheduler my_scheduler; //2017/11/27日,仍然存在BUG。真多线程下调度,存在有协程无法被调度完成的BUG | |||||
local_scheduler my_scheduler; //2017/12/14日,仍然存在BUG。真多线程下调度,存在有协程无法被调度完成的BUG | |||||
go test_channel_consumer(c, BATCH); | go test_channel_consumer(c, BATCH); | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); | ||||
#endif | |||||
std::cout << "Read OK\r\n"; | std::cout << "Read OK\r\n"; | ||||
}); | }); | ||||
} | } | ||||
#if !RESUMEF_ENABLE_MULT_SCHEDULER | |||||
std::this_thread::sleep_for(100ms); | |||||
scheduler::g_scheduler.run_until_notask(); | |||||
#endif | |||||
for(auto & th : read_th) | for(auto & th : read_th) | ||||
th.join(); | th.join(); | ||||
write_th.join(); | write_th.join(); | ||||
std::cout << "OK" << std::endl; | |||||
std::cout << "OK: counter = " << gcounter.load() << std::endl; | |||||
_getch(); | _getch(); | ||||
} | } |
<ClCompile> | <ClCompile> | ||||
<WarningLevel>Level3</WarningLevel> | <WarningLevel>Level3</WarningLevel> | ||||
<Optimization>Disabled</Optimization> | <Optimization>Disabled</Optimization> | ||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;RESUMEF_DEBUG_COUNTER=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;RESUMEF_DEBUG_COUNTER=0;RESUMEF_ENABLE_MULT_SCHEDULER=0;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
<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> |