如何实现始终返回调用者strand的boost::asio::awaitable?
解决方案:Boost ASIO C++20协程的strand上下文保持问题
你的核心问题在于:Boost ASIO的awaitable不会自动保存调用者的执行上下文(strand)。当你co_await另一个awaitable时,协程会在被调用方的最后一个执行上下文(也就是Object2的strand)中恢复,而非自动回到调用方的strand,导致后续访问Object1的成员变量时存在线程安全风险。
方法一:手动绑定调用者strand到awaitable
在调用m_Object2.readValue()时,使用boost::asio::bind_executor将当前Object1的strand绑定到awaitable的完成回调上,确保协程恢复时回到Object1的strand:
boost::asio::awaitable<int> Object1::getValue() { // 简化strand检查:dispatch会自动判断是否在strand内,无需手动if co_await boost::asio::dispatch(m_Object1Strand, boost::asio::use_awaitable); // 绑定调用者strand,确保恢复时回到Object1的strand auto value = co_await boost::asio::bind_executor(m_Object1Strand, m_Object2.readValue()); auto result = value * m_Member; // 现在处于Object1的strand中,安全访问成员 co_return result; } boost::asio::awaitable<int> Object2::readValue() { co_await boost::asio::dispatch(m_Object2Strand, boost::asio::use_awaitable); co_return m_SomeLocalState; }
方法二:通用包装器自动捕获调用者上下文
如果不想每次调用都手动写bind_executor,可以实现一个通用包装函数,自动捕获当前协程的executor(strand),并将其绑定到目标awaitable的完成处理上:
template <typename Awaitable> auto resume_on_caller_executor(Awaitable&& awaitable) { auto caller_exec = co_await boost::asio::this_coro::executor; return boost::asio::bind_executor(caller_exec, std::forward<Awaitable>(awaitable)); }
之后调用时只需包装目标awaitable即可:
boost::asio::awaitable<int> Object1::getValue() { co_await boost::asio::dispatch(m_Object1Strand, boost::asio::use_awaitable); auto value = co_await resume_on_caller_executor(m_Object2.readValue()); auto result = value * m_Member; co_return result; }
关键原理说明
boost::asio::this_coro::executor可以获取当前协程所在的执行上下文(strand)。bind_executor会将awaitable的完成回调关联到指定的executor,确保协程恢复时在该executor上执行。- 使用
dispatch替代手动检查running_in_this_thread(),是因为dispatch会智能判断:如果当前已经在目标strand内,则立即继续执行;否则将任务投递到strand队列,代码更简洁且不易出错。
内容的提问来源于stack exchange,提问作者coko
相关产品推荐
相关产品推荐

