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 the
boost::asio::error::operation_aborted
error.
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_aborted
error 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.
For instance, a write operation may complete successfully while you are inside a handler but before you have got around to calling socket cancel, causing its completion handler to be posted to the queue. As I understand it, the error code is determined by the status of the operation that completed, not the state of the socket at the time the handler is picked off the queue and executed.
Consider two connections establishing at the same time. Both handlers will fire, one will be handled first, second is in the queue (or being handled on a different thread). One can think of more examples like that.
So in order to implement your requirement you need a bit more logic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With