I'm migrating my asio application from its stackful coroutines to c++20 stackless coroutines. I have an existing class method that looks like this:
int my_async_op(asio::yield_context yield) {
using tResult = asio::async_result<asio::yield_context, void(boost::system::error_code, int)>;
tResult::completion_handler_type handler(yield);
tResult result(handler);
...
boost::system::error_code ec;
asio::some_async_op(yield[ec]);
...
handler(boost::system::error_code(), 42);
return result.get();
}
...and is called like this:
boost::system::error_code ec;
x = my_async_op(yield[ec]);
When migrating to C++20 stackless coroutines, chaining is required and a skeleton of my function now looks something like this:
asio::awaitable<int> my_async_op(...) {
...
boost::system::error_code ec;
co_await asio::some_async_op(net::redirect_error(net::use_awaitable, ec));
...
co_return 42;
}
...but is called like this:
boost::system::error_code ec;
x = co_await my_async_op(net::redirect_error(net::use_awaitable, ec));
So the skeleton needs updating to take a completion token, the same as native asio async ops, but I can find a reference example to work off of and I admit to finding asio source code difficult to parse.
Any guidance or references would be appreciated.
Edit: I think I'm getting close with asio::async_initiate per http://open-std.org/JTC1/SC22/WG21/docs/papers/2019/p1943r0.html . My function now looks like this:
template<typename T>
auto my_async_op<T&& token) {
return asio::async_initiate<T, void(boost::system::error_code, int)>(
[&](auto handler)->void {
...
boost::system::error_code ec;
co_await asio::some_async_op(asio::redirect_error(asio::use_awaitable, ec));
...
handler(boost::system::error_code(), 42);
},
token
);
}
Only problem is that I get a compiler error on that nested co_await call:
XXX.h:97:12: error: unable to find the promise type for this coroutine
97 | co_await asio::some_async_op(net::redirect_error(net::use_awaitable, ec));
Will keep grinding away.
Edit: Looking into this now... https://github.com/chriskohlhoff/asio/issues/795
If your requirement is to write your own async_xyz function you can use async_initiate. You should use another thread to run the function on.
I do this to compute a hash on a boost thread pool.
For example:
template <boost::asio::completion_token_for<void (std::string)> CompletionToken>
auto
async_hash (boost::asio::thread_pool &pool, boost::asio::io_context &io_context, std::string const &password, CompletionToken &&token)
{
return boost::asio::async_initiate<CompletionToken, void (std::string)> (
[&] (auto completion_handler, std::string const &passwordToHash) {
auto io_eq = boost::asio::prefer (io_context.get_executor (), boost::asio::execution::outstanding_work.tracked);
boost::asio::post (pool, [&, io_eq = std::move (io_eq), completion_handler = std::move (completion_handler), passwordToHash] () mutable {
auto hashedPw = pw_to_hash (passwordToHash);
boost::asio::post (io_eq, [hashedPw = std::move (hashedPw), completion_handler = std::move (completion_handler)] () mutable { completion_handler (hashedPw); });
});
},
token, password);
}
And on the call side you can call it like the other async_xyz functions inside a coroutine:
auto hashedPw = co_await async_hash (pool, io_context, createAccountObject.password, boost::asio::use_awaitable);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.