如何实现可co_await的延迟绑定回调以在strand上执行协程?
问题与解决方案
问题描述
现有处理类pdu通过运行时延迟绑定的回调触发逻辑,该类由协程调用,但回调需触发另一个协程target_co_routine,且要求在turn()返回前于同一strand上完成。当前使用std::function<void(int)>作为回调类型,无法支持协程的co_await,直接尝试会报错:
error: no matching member function for call to 'await_transform'
原代码如下:
struct pdu { void turn() { callback(5); } /* Not possible due to std::function but preferred boost::asio::awaitable<void> turn () { co_await callback(5); } */ using callback_t = std::function<void(int)>; pdu (callback_t callback) : callback(callback) {} callback_t callback; }; boost::asio::awaitable<void> target_co_routine(int x) { std::cout << "In target coroutine with parameter " << x << std::endl; co_return; } /*! * @param strand that this coroutine is already running on */ boost::asio::awaitable<int> my_coroutine(boost::asio::strand<boost::asio::io_context::executor_type>& strand,std::shared_ptr<demo::scope_stuff>) { std::cout << "In my coroutine" << std::endl; pdu my_pdu{[&strand](int x){ //Not feasible since the strand is already blocked. // Can neither release/defer as it would break the order of execution nor use a dispatch semantic auto f = boost::asio::co_spawn(strand,target_co_routine(x),boost::asio::use_future); f.get(); }}; my_pdu.turn(); co_return 5; }
可行方案
1. 修改回调类型为返回awaitable的函数
将callback_t定义为返回boost::asio::awaitable<void>的函数类型,这样turn()可以设计为协程并直接co_await回调结果,完全符合协程异步逻辑:
struct pdu { boost::asio::awaitable<void> turn() { co_await callback(5); } // 定义返回awaitable的回调类型 using callback_t = std::function<boost::asio::awaitable<void>(int)>; pdu(callback_t callback) : callback(callback) {} callback_t callback; };
在my_coroutine中,只需co_await my_pdu.turn(),回调内部直接co_await目标协程即可,无需阻塞操作:
boost::asio::awaitable<int> my_coroutine(boost::asio::strand<boost::asio::io_context::executor_type>& strand,std::shared_ptr<demo::scope_stuff>) { std::cout << "In my coroutine" << std::endl; pdu my_pdu{[&strand](int x) -> boost::asio::awaitable<void> { // 回调内直接co_await目标协程,自动继承当前strand的执行上下文 co_await target_co_routine(x); }}; // 等待turn()完成 co_await my_pdu.turn(); co_return 5; }
2. 关键注意事项
std::function完全支持存储返回awaitable的函数,之前的错误是因为尝试co_await返回void的函数对象,而非返回awaitable的类型。- 当在strand上的协程中调用回调时,回调会自动继承当前的executor(strand),因此
co_await target_co_routine(x)会自动在strand上执行,无需额外调用co_spawn。 - 绝对避免在strand上使用
use_future+get(),这会导致线程阻塞,违反异步设计原则,甚至引发死锁(strand等待当前协程完成,而get()又等待strand上的新任务)。
内容的提问来源于stack exchange,提问作者Superlokkus
相关产品推荐
相关产品推荐

