Reputation: 8239
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::write
on 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
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
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
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