boost::asio::spawn yield as callback

前端 未结 3 496
终归单人心
终归单人心 2020-12-28 08:57

I\'m trying to rewrite a project using boost::asio::spawn coroutines. Some parts of the project cannot be changed. For example, the storage protocol library is

相关标签:
3条回答
  • 2020-12-28 09:20

    Great thanks to free_coffe i managed this to work. Posting solution for my case, possibly someone need it.

    template <class CompletionToken>
    RequestResult async_foo(Packet &pkt, CompletionToken&& token) {
       typename boost::asio::handler_type< CompletionToken, void(RequestResult) >::type handler( std::forward<CompletionToken>(token) );
      boost::asio::async_result<decltype(handler)> result(handler);
      storage_api->writePacket(pkt, handler);
      return result.get();
    }
    

    Later we can use this proxy:

    RequestResult res = async_foo(pkt, std::forward<boost::asio::yield_context>(yield) );
    
    0 讨论(0)
  • 2020-12-28 09:29

    Looks like the best documentation for this feature can be found in a C++ standard proposal written by the boost asio author:

    N4045 – Library Foundations for Asynchronous Operations, Revision 2

    See section 9.1 which says:

    handler_type_t<CompletionToken, void(error_code, size_t)>   #3
      handler(std::forward<CompletionToken>(token));
    

    3: The completion token is converted into a handler, i.e. a function object to be called when the asynchronous operation completes. The signature specifies the arguments that will be passed to the handler.

    I guess in your case the CompletionToken template argument will actually be boost::asio::yield_context and handler_type converts it to a callback object.


    Here is the code from section 9.1 updated to call your async_request_data function:

    template <class CompletionToken>
    auto async_foo(uint64_t item_id, CompletionToken&& token)
    {
      handler_type_t<CompletionToken, void(Request_result *)>
        handler(std::forward<CompletionToken>(token));
    
      async_result<decltype(handler)> result(handler);  
    
      async_request_data(item_id, handler);
    
      return result.get();  
    }
    
    0 讨论(0)
  • 2020-12-28 09:37

    Thanks to @PSIAlt and @free_coffee I know how to use callback functions in stackful coroutine.

    Here is a simple example just for asio newbies(like me :D)

    https://gist.github.com/chenfengyuan/4d764b0bca82a42c05a9

    #include <iostream>
    #include <boost/asio.hpp>
    #include <boost/date_time/posix_time/posix_time.hpp>
    #include <boost/asio/spawn.hpp>
    #include <memory>
    
    void bar(boost::asio::io_service &io, std::function<void()> cb){
        auto ptr = std::make_shared<boost::asio::deadline_timer>(io, boost::posix_time::seconds(1));
        ptr->async_wait([ptr, cb](const boost::system::error_code&){cb();});
    }
    
    template<typename Handler>
    void foo(boost::asio::io_service &io, Handler && handler){
        typename boost::asio::handler_type<Handler, void()>::type handler_(std::forward<Handler>(handler));
        boost::asio::async_result<decltype(handler_)> result(handler_);
        bar(io, handler_);
        result.get();
        return;
    }
    
    int main()
    {
      boost::asio::io_service io;
      boost::asio::spawn(io, [&io](boost::asio::yield_context yield){
          foo(io, yield);
          std::cout << "hello, world!\n";
      });
    
      io.run();
    
      return 0;
    }
    
    0 讨论(0)
提交回复
热议问题