My code uses boost::asio and io_service in a single thread to perform various socket operations. All operations are asynchronous and every handler depends on the boost::system::error_code (particularly boost::asio::error::operation_aborted) to determine the result of the operation.
It’s been working perfectly well until I changed the logic to make several concurrent connections and pick the fastest one. That is, when the first async_read_some handler fires, I cancel other sockets (shutdown, close – everything) and proceed with the current one. In 95% of cases other sockets’ read handlers are invoked with the operation_aborted error. However sometimes, these read handlers are invoked without errors, telling me that they have successfully received N bytes.
But the documentation for socket::cancel() states:
This function causes all outstanding asynchronous connect, send and
receive operations to finish immediately, and the handlers for
cancelled operations will be passed theboost::asio::error::operation_abortederror.
So, the questions: Can I really rely on the operation_aborted error in production code? If I can, is it a bug in Asio from boost 1.46.1? If I can’t, is there any official documentation regarding this?
Ok, the answers:
operation_abortederror only.If the timer has already expired when cancel() is called, then the handlers for asynchronous wait operations will:
Basically, I was wrong in assumption that if I use a single thread for io_service, then every operation will be blocked while some handler executes.
The behavior I’m reporting actually makes a lot of sense and it seems that everyone who uses Asio knows that. I’ve combed through Asio’s mailing lists and have found a lot of discussion on the subject here, here, here and here.