Handling boost asio timer cancelation

2019-07-27 07:48发布

问题:

Consider the following code that simulates a synchronous connect with timeout using async connect:

{
    boost::asio::steady_timer timer{io_service, timeout};
    timer.async_wait([&socket](boost::system::error_code const& code) {
        if (!code)
            socket.close();
        });

    auto future = boost::asio::async_connect(socket, endpoint, boost::asio::use_future);
    future.get();
}

/* detect post-success cancelation? */
if (!socket.is_open()) {
}

If I understand asio documentation correctly, I cannot guarantee that the timer handler won't close the socket after is_open() has already returned true, because this sequence of events is possible:

  1. connect completes successfully
  2. timer expires, queuing the handler with code == success
  3. timer is destroyed, but the already queued handler can't be recalled
  4. is_open() returns true, so we think we're golden
  5. handler runs, canceling our socket because code == success
  6. future operations using the socket fail because we erroneously believed it's still open

How do I fix this code to make it safe against this scenario?