The code below prints to the console when both timer1 and timer2 have finished. How can I change it to print when either timer1 or timer2 finishes, and then cancel the other timer.
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
int main() {
boost::asio::io_context io;
boost::asio::deadline_timer timer1(io, boost::posix_time::seconds(5));
boost::asio::deadline_timer timer2(io, boost::posix_time::seconds(1));
boost::asio::spawn(io, [&](boost::asio::yield_context yield){
timer1.async_wait(yield);
timer2.async_wait(yield);
std::cout << "Both timer1 and timer2 have finished" << std::endl;
});
io.run();
}
I took the question to mean "how do you
async_wat_any(timer1, timer2, ..., yield).The other answer is correct in pointing at callback completion-handlers to provide this, but they don't provide the glue back to a single coroutine.
Now Asio's async operations abstract away the difference between all the invocation styles (callback, use_future, use_awaitable, yield_context etc...) - bringing them all back under the "callback" style essentially.
Therefore you can make your own async intiation that ties these torgether, rough sketch:
Now in your coroutine you can say:
and it will return when the first one completes.
Let's Demo
Also, making it more generic, not hard-coding the timer type. In fact on a Windows environment you will be able to wait on Waitable Objects (like Event, Mutex, Semaphore) with the same interface:
We'll write a demo coroutine like:
This prints Live On Coliru
Notes, Caveats
Tricky bits:
It's hard to decide what executor to bind the handlers to, since there could be multiple associated executors. However, since you're using coroutines, you'll always get the correct
strand_executorassociated with theyield_contextIt's important to do the cancellations before invoking the caller's completion token, because otherwise the coroutine is already resumed before it was safe, leading to potential lifetime issues
Speaking of which, since now we post async operations outside the coroutine with the coroutine suspended, we will need a work-guard, because coroutines are not work.