ã¯ããã«
ã³ãŒã«ããã¯é¢æ°ã®äœ¿çšã¯ãBoost.Asioã©ã€ãã©ãªïŒã ãã§ãªãïŒã䜿çšããŠãããã¯ãŒã¯ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããäžè¬çãªã¢ãããŒãã§ãã ãã®ã¢ãããŒãã®åé¡ã¯ãããŒã¿äº€æãããã³ã«ã®ããžãã¯ãè€éã«ããŠããéãã³ãŒãã®å¯èªæ§ãšä¿å®æ§ã®æªåã§ã[1] ã
ã³ãŒã«ããã¯ã®ä»£æ¿ãšããŠãã³ã«ãŒãã³ã䜿çšããŠéåæã³ãŒããèšè¿°ã§ããŸããéåæã³ãŒãã®å¯èªæ§ã¬ãã«ã¯ãåæã³ãŒãã®å¯èªæ§ã«è¿ããªããŸãã Boost.Asioã¯ãBoost.Coroutineã©ã€ãã©ãªã䜿çšããŠã³ãŒã«ããã¯ãåŠçããæ©èœãæäŸããããšã«ããããã®ã¢ãããŒãããµããŒãããŠããŸãã
Boost.Coroutineã¯ãçŸåšã®ã¹ã¬ããã®å®è¡ã³ã³ããã¹ããä¿åããããšã«ãããã³ã«ãŒãã³ãå®è£
ããŸãã ãã®ã¢ãããŒãã¯ãæ°ããããŒã¯ãŒãco_returnãco_yieldãco_awaitãå°å
¥ããMicrosoftã®ææ¡ã«ãããC ++æšæºã®æ¬¡ã®ãšãã£ã·ã§ã³ã«å«ããããã«ç«¶åããŸããã Microsoftã®ææ¡ã¯ãæè¡ä»æ§ïŒTSïŒ [2]ã®ã¹ããŒã¿ã¹ãååŸããŠãããæšæºã«ãªãå¯èœæ§ãé«ããªã£ãŠããŸãã
èšäº[3]ã¯ãCoroutines TSããã³boost :: futureã§Boost.Asioã䜿çšããæ¹æ³ã瀺ããŠããŸãã ç§ã®èšäºã§ã¯ãããŒã¹ããªãã§è¡ãæ¹æ³::å°æ¥ã瀺ããããšæããŸãã Boost.Asioã®éåæTCPãšã³ãŒãµãŒããŒã®äŸãããŒã¹ãšããŠãCoroutines TSã®ã³ã«ãŒãã³ã䜿çšããŠå€æŽããŸãã
ãã®èšäºã®å·çæç¹ã§ãCoroutines TSã¯Visual C ++ 2017ããã³clang 5.0ã³ã³ãã€ã©ã«å®è£
ãããŠããŸãã clangã䜿çšããŸãã C ++ 20æšæºïŒ-std = c ++ 2aïŒããã³Coroutines TSïŒ-fcoroutines-tsïŒã®å®éšçãµããŒããæå¹ã«ããã«ã¯ãã³ã³ãã€ã©ãã©ã°ãèšå®ããå¿
èŠããããŸãã ãŸããããããŒ<experimental / coroutine>ãå«ããå¿
èŠããããŸãã
ãœã±ããããèªã¿åãããã®ã³ã«ãŒãã³
å
ã®äŸã§ã¯ããœã±ããããèªã¿åãããã®é¢æ°ã¯æ¬¡ã®ããã«ãªããŸãã
void do_read() { auto self(shared_from_this()); socket_.async_read_some( boost::asio::buffer(data_, max_length), [this, self](boost::system::error_code ec, std::size_t length) { if (!ec) { do_write(length); } }); }
ãœã±ããããéåæèªã¿åããéå§ããããŒã¿ãåä¿¡ããŠââãã®éä¿¡ãéå§ãããšãã«åŒã³åºãããã³ãŒã«ããã¯ãèšå®ããŸãã ãªãªãžãã«ã®é²é³æ©èœã¯æ¬¡ã®ããã«ãªããŸãã
void do_write(std::size_t length) { auto self(shared_from_this()); boost::asio::async_write( socket_, boost::asio::buffer(data_, length), [this, self](boost::system::error_code ec, std::size_t ) { if (!ec) { do_read(); } }); }
ãœã±ãããžã®ããŒã¿ã®æžã蟌ã¿ãæåãããšãéåæèªã¿åããåã³éå§ããŸãã æ¬è³ªçã«ãããã°ã©ã ããžãã¯ã¯ã«ãŒãïŒæ¬äŒŒã³ãŒãïŒã«çž®å°ãããŸãã
while (!ec) { ec = read(buffer); if (!ec) { ec = write(buffer); } }
ãããæç€ºçãªã«ãŒãã®åœ¢åŒã§ãšã³ã³ãŒããããšäŸ¿å©ã§ããããã®å Žåã¯åææäœã§èªã¿åããšæžã蟌ã¿ãè¡ãå¿
èŠããããŸãã ããã¯ã1ã€ã®å®è¡ã¹ã¬ããã§è€æ°ã®ã¯ã©ã€ã¢ã³ãã»ãã·ã§ã³ãåæã«åŠçãããããé©åã§ã¯ãããŸããã ã³ã«ãŒãã³ãå©ãã«ãªããŸãã do_readïŒïŒé¢æ°ã次ã®ããã«æžãçŽããŸãã
void do_read() { auto self(shared_from_this()); const auto[ec, length] = co_await async_read_some( socket_, boost::asio::buffer(data_, max_length)); if (!ec) { do_write(length); } }
co_awaitããŒã¯ãŒãïŒããã³co_yieldããã³co_returnïŒã䜿çšãããšã颿°ãã³ã«ãŒãã³ã«å€ãããŸãã ãã®ãããªé¢æ°ã«ã¯ãç¶æ
ïŒããŒã«ã«å€æ°ã®å€ïŒãç¶æããªããå®è¡ãäžæïŒäžæïŒãããã€ã³ããããã€ããããŸãïŒäžæãã€ã³ãïŒã æåŸã®åæ¢ããéå§ããŠãåŸã§ã³ã«ãŒãã³ã®å®è¡ãåéïŒåéïŒã§ããŸãã ãã®é¢æ°ã®co_awaitããŒã¯ãŒãã¯äžæåæ¢ãã€ã³ããäœæããŸããéåæèªã¿åããéå§ãããåŸãdo_readïŒïŒã³ã«ãŒãã³ã®å®è¡ã¯èªã¿åããå®äºãããŸã§äžæåæ¢ãããŸãã 颿°ããã®æ»ãã¯ãããŸããããããã°ã©ã ã®å®è¡ã¯ã³ã«ãŒãã³ãåŒã³åºããæç¹ããç¶ç¶ãããŸãã ã¯ã©ã€ã¢ã³ããæ¥ç¶ãããšãã»ãã·ã§ã³:: startïŒïŒãåŒã³åºãããŸãããã®ã»ãã·ã§ã³ã§ã¯ãdo_readïŒïŒãåããŠåŒã³åºãããŸãã éåæèªã¿åãã®éå§åŸãstartïŒïŒé¢æ°ã¯åŒãç¶ãå®è¡ãããããããæ»ããæ¬¡ã®æ¥ç¶ãéå§ãããŸãã æ¬¡ã«ãasync_acceptïŒïŒåŒæ°ãã³ãã©ãŒãåŒã³åºããAsioã®ã³ãŒãã®å®è¡ãç¶ç¶ãããŸãã
co_awaitããžãã¯ãæ©èœããããã«ã¯ããã®åŒïŒãã®äŸã§ã¯async_read_someïŒïŒé¢æ°ïŒãç¹å®ã®ã³ã³ãã©ã¯ãã«äžèŽããã¯ã©ã¹ã®ãªããžã§ã¯ããè¿ãå¿
èŠããããŸãã async_read_someïŒïŒã®å®è£
ã¯ãèšäº[3]ã®è§£èª¬ããåãããŠããŸãã
template <typename SyncReadStream, typename DynamicBuffer> auto async_read_some(SyncReadStream &s, DynamicBuffer &&buffers) { struct Awaiter { SyncReadStream &s; DynamicBuffer buffers; std::error_code ec; size_t sz; bool await_ready() { return false; } void await_suspend(std::experimental::coroutine_handle<> coro) { s.async_read_some(std::move(buffers), [this, coro](auto ec, auto sz) mutable { this->ec = ec; this->sz = sz; coro.resume(); }); } auto await_resume() { return std::make_pair(ec, sz); } }; return Awaiter{s, std::forward<DynamicBuffer>(buffers)}; }
async_read_someïŒïŒã¯ãco_awaitãå¿
èŠãšããã³ã³ãã©ã¯ããå®è£
ããAwaiterã¯ã©ã¹ã®ãªããžã§ã¯ããè¿ããŸãã
- await_readyïŒïŒã¯ãéåææäœã®çµæãæ¢ã«æºåãã§ããŠãããã©ããã確èªããããã«ãåŸ
æ©ã®éå§æã«åŒã³åºãããŸãã çµæãååŸããã«ã¯ãããŒã¿ãèªã¿åããããŸã§åžžã«åŸ
æ©ããå¿
èŠããããããfalseãè¿ããŸãã
- await_suspendïŒïŒã¯ãåŒã³åºãå
ã®ã³ã«ãŒãã³ãäžæåæ¢ãããåã«åŒã³åºãããŸãã ããã§éåæèªã¿åããéå§ããéåææäœã®çµæãAwaiterã¯ã©ã¹ã®ã¡ã³ããŒå€æ°ã«ä¿åããŠã³ã«ãŒãã³ãåéãããã³ãã©ãŒãæž¡ããŸãã
- await_resumeïŒïŒ-ãã®é¢æ°ã®æ»ãå€ã¯ãco_awaitãå®è¡ããçµæã«ãªããŸãã 以åã«ä¿åããéåææäœã®çµæãè¿ãã ãã§ãã
ããã°ã©ã ããã«ãããããšãããšãã³ã³ãã€ã«ãšã©ãŒãçºçããŸãã
error: this function cannot be a coroutine: 'std::experimental::coroutines_v1::coroutine_traits<void, session &>' has no member named 'promise_type' void do_read() { ^
çç±ã¯ãã³ã«ãŒãã³ã«å¯ŸããŠãç¹å®ã®ã³ã³ãã©ã¯ããå®è£
ããå¿
èŠãããããã§ãã ããã¯ãstd :: Experimental :: coroutine_traitsãã³ãã¬ãŒãã®ç¹æ®åã䜿çšããŠè¡ãããŸãã
template <typename... Args> struct std::experimental::coroutine_traits<void, Args...> { struct promise_type { void get_return_object() {} std::experimental::suspend_never initial_suspend() { return {}; } std::experimental::suspend_never final_suspend() { return {}; } void return_void() {} void unhandled_exception() { std::terminate(); } }; };
voidåã®æ»ãå€ãšä»»æã®æ°ãšåã®ãã©ã¡ãŒã¿ãŒãæã€ã³ã«ãŒãã³çšã«coroutine_traitsãç¹æ®åããŸããã do_readïŒïŒã³ã«ãŒãã³ã¯ãã®èª¬æã«é©åããŸãã ãã³ãã¬ãŒãã®ç¹æ®åã«ã¯ãæ¬¡ã®æ©èœãæã€promise_typeã¿ã€ããå«ãŸããŸãã
- get_return_objectïŒïŒãåŒã³åºãããŠãã³ã«ãŒãã³ãåŸã§åããŠè¿ããªããžã§ã¯ããäœæããŸãã ãã®å Žåãdo_readïŒïŒã¯äœãè¿ããªããããäœãäœæããå¿
èŠã¯ãããŸããã
- initial_suspendïŒïŒã¯ãæåã®åŒã³åºãã®åã«ã³ã«ãŒãã³ãäžæããããã©ãããæ±ºå®ããŸãã 顿šã¯ãWindowsã§äžæãããã¹ã¬ãããéå§ããããšã§ãã æåã«åæ¢ããããšãªãå®è¡ããã«ã¯do_readïŒïŒãå¿
èŠãªã®ã§ãsuspend_neverãè¿ããŸãã
- final_suspendïŒïŒã¯ãå€ãè¿ããŠçµäºããåã«ã³ã«ãŒãã³ãäžæãããã©ãããæ±ºå®ããŸãã suspend_neverãè¿ããŸãã
- return_voidïŒïŒã¯ãã³ã«ãŒãã³ãäœãè¿ããªãããšãã³ã³ãã€ã©ãŒã«äŒããŸãã
- ã³ã«ãŒãã³å
ã§äŸå€ãã¹ããŒãããã³ã«ãŒãã³å
ã§åŠçãããªãã£ãå Žåãunhandled_exceptionïŒïŒãã¹ããŒãããŸãã ãã®å Žåãããã°ã©ã ã¯ã¯ã©ãã·ã¥ããŸãã
ããã§ãtelnetã䜿çšããŠè€æ°ã®æ¥ç¶ãéãããšã«ããããµãŒããŒãèµ·åããŠãã®ããã©ãŒãã³ã¹ã確èªã§ããŸãã
ãœã±ããã«æžã蟌ãããã®ã³ã«ãŒãã³
do_writeïŒïŒæžã蟌ã¿é¢æ°ã¯ãã³ãŒã«ããã¯ã®äœ¿çšã«åºã¥ããŠããŸãã ä¿®æ£ããŠãã ããã do_writeïŒïŒã次ã®ããã«æžãæããŸãã
auto do_write(std::size_t length) { auto self(shared_from_this()); struct Awaiter { std::shared_ptr<session> ssn; std::size_t length; std::error_code ec; bool await_ready() { return false; } auto await_resume() { return ec; } void await_suspend(std::experimental::coroutine_handle<> coro) { const auto[ec, sz] = co_await async_write( ssn->socket_, boost::asio::buffer(ssn->data_, length)); this->ec = ec; coro.resume(); } }; return Awaiter{self, length}; }
ãœã±ããã«æžã蟌ãããã®åŸ
æ©å¯èœãªã©ãããŒãäœæããŸãããã
template <typename SyncReadStream, typename DynamicBuffer> auto async_write(SyncReadStream &s, DynamicBuffer &&buffers) { struct Awaiter { SyncReadStream &s; DynamicBuffer buffers; std::error_code ec; size_t sz; bool await_ready() { return false; } auto await_resume() { return std::make_pair(ec, sz); } void await_suspend(std::experimental::coroutine_handle<> coro) { boost::asio::async_write( s, std::move(buffers), [this, coro](auto ec, auto sz) mutable { this->ec = ec; this->sz = sz; coro.resume(); }); } }; return Awaiter{s, std::forward<DynamicBuffer>(buffers)}; }
æåŸã®ã¹ãããã¯ãdo_readïŒïŒãæç€ºçãªã«ãŒããšããŠæžãçŽãããšã§ãã
void do_read() { auto self(shared_from_this()); while (true) { const auto[ec, sz] = co_await async_read_some( socket_, boost::asio::buffer(data_, max_length)); if (!ec) { auto ec = co_await do_write(sz); if (ec) { std::cout << "Error writing to socket: " << ec << std::endl; break; } } else { std::cout << "Error reading from socket: " << ec << std::endl; break; } } }
ããã°ã©ã ããžãã¯ã¯ãåæã³ãŒãã«è¿ã圢åŒã§èšè¿°ãããããã«ãªããŸããããéåæã§å®è¡ãããŸãã è»èã®ãã©ã€ã¯ãdo_writeïŒïŒã®æ»ãå€çšã«è¿œå ã®åŸ
æ©å¯èœã¯ã©ã¹ãäœæããå¿
èŠããã£ãããšã§ãã ããã¯ãã³ã«ãŒãã³TSã®æ¬ ç¹ã®1ã€-co_awaitã®éåæåŒã³åºãã®ã¹ã¿ãã¯ãžã®åºãã[4]ã瀺ããŠããŸãã
ãµãŒããŒã®åäœæ::ã³ã«ãŒãã³å
ã®do_acceptïŒïŒé¢æ°ã¯æŒç¿ãšããŠæ®ãããŠããŸãã ããã°ã©ã ã®å
šæã¯GitHubã«ãããŸã ã
ãããã«
Boost.AsioãšCoroutines TSã䜿çšããŠãéåæãããã¯ãŒã¯ã¢ããªã±ãŒã·ã§ã³ã®ããã°ã©ãã³ã°ãæ€èšããŸããã ãã®ã¢ãããŒãã®å©ç¹ã¯ãåæã«è¿ã圢ã«ãªããããã³ãŒãã®å¯èªæ§ãåäžããããšã§ãã æ¬ ç¹ã¯ãCoroutines TSã«å®è£
ãããã³ã«ãŒãã³ã¢ãã«ããµããŒãããããã«è¿œå ã®ã©ãããŒãäœæããå¿
èŠãããããšã§ãã
åç
§è³æ
- éåææ§ïŒããã¯ãã¥ã¶ãã¥ãŒãã£ãŒ
- ã¯ãŒãã³ã°ãã©ãããã³ã«ãŒãã³ã®C ++æ¡åŒµæ©èœã®æè¡ä»æ§
- Boost C ++ã©ã€ãã©ãªã§ã®C ++ã³ã«ãŒãã³ã®äœ¿çš
- C ++ 17ã§awaitã䜿çšããŠã³ã«ãŒãã³ãåãå
¥ããããšã«å察