c++ - asio 自定义异步函数和 c++20 协程
问题描述
我正在将我的 asio 应用程序从它的 stackful coroutines 迁移到 c++20 stackless coroutines。我有一个现有的类方法,如下所示:
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();
}
...并像这样调用:
boost::system::error_code ec;
x = my_async_op(yield[ec]);
当迁移到 C++20 无堆栈协同程序时,需要链接,我的函数的骨架现在看起来像这样:
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;
}
...但是这样称呼:
boost::system::error_code ec;
x = co_await my_async_op(net::redirect_error(net::use_awaitable, ec));
因此,骨架需要更新以获取完成令牌,与本机 asio 异步操作相同,但我可以找到一个参考示例来解决,我承认发现 asio 源代码难以解析。
任何指导或参考将不胜感激。
编辑:我想我已经接近 asio::async_initiate per http://open-std.org/JTC1/SC22/WG21/docs/papers/2019/p1943r0.html。我的函数现在看起来像这样:
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
);
}
唯一的问题是我在嵌套的 co_await 调用上遇到编译器错误:
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));
会一直磨下去。
编辑:现在调查这个...... https://github.com/chriskohlhoff/asio/issues/795
解决方案
如果您的要求是编写自己的 async_xyz 函数,则可以使用 async_initiate。您应该使用另一个线程来运行该功能。
我这样做是为了计算提升线程池上的哈希值。
例如:
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);
}
在调用端,您可以像协程中的其他 async_xyz 函数一样调用它:
auto hashedPw = co_await async_hash (pool, io_context, createAccountObject.password, boost::asio::use_awaitable);
推荐阅读
- javascript - 试图在 FireBase 中显示购物车对象中的项目总数
- c++ - Eclipse 不在 Windows (C++) 中编译 .exe
- javascript - 向窗口添加属性有什么意义?
- java - 如何制作将显示在所有网格布局(Java GUI)上的单个背景图像?
- python - 来自终端和文件的请求的不同状态响应
- python-3.x - 如何列出 Windows 目录中的所有“带路径的文件”,包括 Python 中的所有子文件夹?
- python - 提高连接到 AWS IOT Core 连接的稳定性
- ruby-on-rails - 如何使用 smarter_csv 为 API 进行大规模创建 - Ruby on Rails
- maven - 在没有 Gradle 的情况下创建 Gradle-Maven C/C++ 包
- c++ - 将成员函数作为构造函数参数调用时出错“变量不是类型名称”