I was using both stackful coroutines (as depicted here: https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/overview/composition/spawn.html) and C++20 coroutines (https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/overview/composition/cpp20_coroutines.html) in my project. Here is an example:
#include <boost/asio.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/spawn.hpp>
#include <iostream>
using namespace boost::asio;
io_context ioctx;
void stackful_coroutine(yield_context yield);
awaitable<void> cxx_coroutine() {
std::cout << "In cxx_coroutine" << std::endl;
co_await spawn(ioctx, stackful_coroutine, use_awaitable);
co_return;
}
void stackful_coroutine(yield_context yield) {
std::cout << "In stackful_coroutine" << std::endl;
}
int main() {
co_spawn(ioctx, cxx_coroutine(), detached);
ioctx.run();
}
This works with no errors and spawn is used as just another asynchronous operation.
However, when I switch the order:
#include <boost/asio.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/spawn.hpp>
#include <iostream>
using namespace boost::asio;
io_context ioctx;
void stackful_coroutine(yield_context yield);
awaitable<void> cxx_coroutine() {
std::cout << "In cxx_coroutine" << std::endl;
co_return;
}
void stackful_coroutine(yield_context yield) {
std::cout << "In stackful_coroutine" << std::endl;
co_spawn(ioctx, cxx_coroutine(), yield);
}
int main() {
spawn(ioctx, stackful_coroutine, detached);
ioctx.run();
}
I get a segmentation fault!
Moreover, I also get a segmentation fault even when I only use stackful coroutines as follows:
#include <boost/asio.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/spawn.hpp>
#include <iostream>
using namespace boost::asio;
io_context ioctx;
void stackful_coroutine(yield_context yield) {
std::cout << "In stackful_coroutine" << std::endl;
spawn(
ioctx, [](auto yc) { std::cout << "Spawn inside spawn" << std::endl; },
yield);
}
int main() {
spawn(ioctx.get_executor(), stackful_coroutine, detached);
ioctx.run();
}
I am not sure if this is a bug, or whether I am missing something...
I am using gcc (Debian 12.2.0-14) 12.2.0 with Boost 1.83.0.
I think you're on to a bug, introduced in Asio 1.24/Boost 1.80.0.
I've noticed a behaviorial change with commit 5bbdc9b Added new spawn() overloads that conform to the requirements for asynchronous operations before¹ and checked before and after.
I can't give a satisfactory suggestion. I can show you what I've tried (based on your last, simplest, example).
None of the alternatives (e.g. inheriting the
yieldcontext for the inner coro, which is deprecated but still exists) work. Note also, the old style doesn't actually achieve the same result anyways, because the innerspawnis not "awaited", regardless of whether theyieldcontext is inherited. ¯\(ツ)/¯ I guess this makes it "not a breaking change" because the functionality didn't exist before Asio 1.24.Note I also experimented with adding work-guards to the inner handlers but it made no difference.
Live On Coliru
Printing e.g.
Vs.
Lastly I made sure to isolate it to Asio-only changes by switching just the ASIO version, instead of all of boost:
I would suggest raising this question at https://github.com/boostorg/asio/issues or (possibly better?) https://github.com/chriskohlhoff/asio/issues