I am trying to use boost ASIO with c++20 coroutines, but I'm struggling to find examples and documentation.
Currently, I have several objects, each owning a strand. They can post tasks to each other, the tasks execute in the strand owned by the callee, then they return to the caller by posting a continuation lambda (bound with bind_executor
) and execution continues on the strand of the caller. This works quite well.
I'd like to replace the continuations with coroutines and co_await
calls to make things more readable, so here's what I thought would do that:
boost::asio::awaitable<int> Object1::getValue()
{
// Ensure we're on the local strand
if (!m_Object1Strand.running_in_this_thread())
{
co_await boost::asio::post(m_Object1Strand, boost::asio::use_awaitable);
}
// Make some call to another object that has its own strand
auto value = co_await m_Object2.readValue();
// Combine the result with some local state
auto result = value * m_Member;
co_return result;
}
boost::asio::awaitable<int> Object2::readValue()
{
// Switch to Object2's local strand
if (!m_Object2Strand.running_in_this_thread())
{
co_await boost::asio::post(m_Object2Strand, boost::asio::use_awaitable);
}
// Do some async work, return a value
co_return m_SomeLocalState;
}
This looks pretty reasonable to me, but it doesn't do what I expect.
The call to m_Object2.readValue()
contains a switch to Object2's strand (since it needs to access the state in that object). Once we've returned to Object1 it seems rather random which strand we end up on. I expected/hoped that ASIO would be smart enough to transparently return me to the strand I originally awaited from, but it seems that is not the case. The access to m_Member
there would be unsafe if we aren't on the right strand.
I figured it may be possible to inherit from boost::asio::awaitable
and make it switch back to the caller's strand somehow, but I've completely failed in figuring out how to do that and I'm wondering if maybe I'm completely off the mark and there is a different pattern I'm supposed to be using.