Reputation: 3989
I have a boost::asio::io_service
running in a thread that performs some operation:
struct clicker
{
clicker(boost::asio::io_service& io) : timer_(io) { wait_for_timer(); }
void stop() { timer_.cancel(); }
void wait_for_timer()
{
timer_.expires_from_now(std::chrono::milliseconds(500));
timer_.async_wait(std::bind(&clicker::wait_completed, this, _1));
}
void wait_completed(const boost::system::error_code& err)
{
if (!err) {
std::cout << "Click" << std::endl;
wait_for_timer();
}
}
boost::asio::steady_timer timer_;
};
int main()
{
boost::asio::io_service io;
clicker cl(io);
std::thread io_thread(&boost::asio::io_service::run, &io);
while (true) { // the run loop
// gather input
if (user_clicked_stop_button()) { cl.stop(); break; }
}
io_thread.join();
}
Now calling stop()
should cancel waiting for the timer and fire wait_completed()
with an error. However, we have a race condition here: at times, stop()
will be called while wait_for_timer()
is running and before the async_wait
has been scheduled. Then, the code will run indefinitely.
What's the recommended way to deal with this situation? A boolean flag inside clicker
that is tested in wait_completed
? A mutex?
This is just a simplified example, in the real code I have several operations running in the io_service
, so calling io_service::stop()
is not an option here.
Upvotes: 0
Views: 2629
Reputation: 15075
Post the action to the io_service thread:
void stop()
{
timer_.get_io_service().post([=] { timer_.cancel(); });
}
(If your compiler is not c++11-compatible, use bind
to create the lambda.)
Upvotes: 2