TheWaterProgrammer
TheWaterProgrammer

Reputation: 8239

how to cancel a `boost::asio::read` operation while it's waiting

I am using boost::asio to transfer data to & fro from client to server. I have a reader thread on client side to read data received on the socket on client side. Please note that I am using boost::asio::read on client side & boost::asio::writeon server side. Not using async_read or async_write. Everything works great.

However when I close my application, 2 out 10 times the app does not cleanly tear down or close properly. It gets hung while closing down The issue is the following:

My closing function gets called when destructors get called during my app's close down. Following is the code of the Close function:

socket.cancel();
socket.close();
boost::system::error_code ec;
socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);

The problem is that the boost::asio::read call does not return when it does not get any data & keeps waiting on it. This should be fine as long as I can cancel it. I am trying to do a socket.cancel on it to cancel all read operations while exiting. However, it doesn't seems to work. I read in some forums that socket.cancel only cancels async_read operations. Is it so ? Then what is the way to cancel a boost::asio::read` operation when my app needs to exit ?

Upvotes: 7

Views: 5900

Answers (3)

Andrew Ames
Andrew Ames

Reputation: 21

The error is due to the call to socket.close() before the call to socket.shutdown(). If you close a socket while there is a pending synchronous read(), you will occasionally get that error. It is really due to an expected data race in the underlying asio socket code.

Try removing the socket.close() call. Assuming your socket is wrapped in some kind of shared_ptr, you can let the socket destructor close the underlying socket.

You will still want to call socket.cancel() and socket.shutdown() explicitly in your use case in order to cancel outstanding operations.

Upvotes: 0

DinoStray
DinoStray

Reputation: 774

boost::system::error_code _error_code;
client_socket_->shutdown(boost::asio::ip::tcp::socket::shutdown_both, _error_code);

Above code help me close sync read immediately.
And sync read wiil return with error code: boost::asio::error::eof
I wonder why your code socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); did not work.

Maybe you should try again.

Upvotes: 0

sehe
sehe

Reputation: 393029

That's the nature of blocking IO.

Indeed socket.cancel() (or even io_service::stop()) will not work on synchronous operations.

The only way to interrupt this is to use socket-level timeouts (but Asio doesn't expose that) or to use asynchronous signals (e.g. pressing Ctrl-C in a terminal sends the child process a SIGINT).

I've previously created a poor-man's wrapper if you insist on running single operations with a timeout:

Upvotes: 5

Related Questions