Prevent io_context::run from returning
io_context::run
runs until all scheduled tasks are completed. After that io_context::run
will return and the caller thread will unblock:
boost::asio::io_context io_context;
// Schedule some tasks
io_context.run();
std::cout << "Job's done! Continue the execution\n";
However sometimes you may need to keep it running regardless if there are tasks to execute or not. Servers we've reviewed so far were always doing async_accept
, so they always had at least one task scheduled, so we didn't really need to keep them running in such a way. However a client doesn't do async_accept
and it's a normal thing for it not to have scheduled tasks at some point at all. To prevent io_context::run
from returning you should use boost::asio::executor_work_guard
(a former io_context::work
which is currently deprecated) class instance. Its name is too long, so let's alias it right away:
using work_guard_type = boost::asio::executor_work_guard<boost::asio::io_context::executor_type>;
boost::asio::io_context io_context;
work_guard_type work_guard(io_context.get_executor());
// Schedule some tasks or not
io_context.run();
std::cout << "Sorry, we'll never reach this!\n";
You still need a way to stop your application somehow, and to stop it gracefully. You may use io_context::stop
function:
boost::asio::io_context io_context;
work_guard_type work_guard(io_context.get_executor());
// Schedule some tasks or not
std::thread watchdog([&]
{
std::this_thread::sleep_for(10s);
io_context.stop(); // That's OK, io_context::stop is thread-safe
});
io_context.run();
std::cout << "We stopped after 10 seconds of running\n";
In that case io_context::run
won't stop right away but do this in the nearest suitable point of time, and the rest of scheduled tasks will be discarded. And that may be exactly what you're needed.
You may also need to wait until all scheduled tasks are completed and return from io_context::run
after that. To do so you just need to destroy io_context::work
class instance. This operation is also thread-safe:
boost::asio::io_context io_context;
auto work_guard = std::make_unique<work_guard_type>(io_context.get_executor());
// Schedule some tasks or not
std::thread watchdog([&]
{
std::this_thread::sleep_for(10s);
work_guard.reset(); // Work guard is destroyed, io_context::run is free to return
});
io_context.run();
std::cout << "We stopped after 10+ seconds of running\n";
If you're going to call io_context::run
once again after it returned, then you should call io_context::reset
before that.