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

3

7

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 ?

Stinkwood answered 6/1, 2017 at 16:31 Comment(0)
K
5

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:

Koweit answered 6/1, 2017 at 19:52 Comment(1)
Seems like I need use async operations to resolve this issue. My C++ which hosts this code is getting used in UI based apps & it is not a problem there because I think the SIGINT is sent to kill the whole app when the UI app gets killed. It is only a problem when the client app is a console app. Anyways, thanks for this explanationStinkwood
C
0
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.

Contrary answered 17/7, 2019 at 7:46 Comment(0)
G
0

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.

Glebe answered 8/12, 2019 at 17:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.