Comparing the new and old code that has changes in functionality, a good candidate can be this change from io_service::work to work_guard: the old just runs, the new has some explicit management enhancements
// Old
boost::asio::io_context::work work(ioContext);
ioContext.run();
// New
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work =
boost::asio::make_work_guard(ioContext);
ioContext.run();
Possible ideas trying a fix (work guard stays alive for the entire duration, with safety-net ):
static void asioFunction() {
// this first
auto work = boost::asio::make_work_guard(ioContext);
try { // make sure it stays alive
ioContext.run();
} catch (...) {
work.reset(); // if shit happens, reset
throw;
}
// guard destroyed when the function exits
}
— this is the new intended usage. Please double-check this if someone can do it —
@smoge The old and new code are really equivalent, so that can’t be the reason for the bug. (For debugging, one could insert a printf statement after ioContext.run() to verify that the ASIO thread does not terminate early.)
AFAICT work_guard is just the replacement for work, similar to io_context vs. io_service. They both do the same thing: they keep the ASIO event loop running – even if there are no outstanding async operations – until they go out of scope. When we call stop on the ioContext, all pending operations, including the work guard, are cancelled and the thread returns.