Thread-safely closing a boost::asio::ip::tcp::socket being used synchronously - c++

Given that the boost::asio::ip::tcp::acceptor and boost::asio::ip::tcp::socket are both marked as non-thread safe as of Boost 1.52.0, is it possible to shutdown a tcp::acceptor currently blocking on accept() from a separate thread?
I've looked at calling boost::asio::io_service::stop() and this looks possible as io_service is thread safe. Would this leave the io_service event loop running until any processing being done on the socket are complete?
I am operating synchronously as this is as simple event loop as part of a bigger program and don't want to create additional threads without good reason which I understand async will do.

Having spent some time looking into this there is only 1 thread safe manner in which this can be achieved: by sending a message to the socket (on a thread not waiting on accept()) telling the thread to close the socket and the acceptor. By doing this the socket and acceptor can be wholly owned by a single thread.
As pointed out separately, io_service is only of use for asynchronous operations.

If your acceptor is in async_accept, you can call ip::tcp::acceptor::cancel() to cancel any async operations on it. Note this may fire handlers in this acceptor with the boost::asio::error::operation_aborted error code.
If you're using synchronous accept, it seems impossible since I think it's not related to io_service at all.

I think your over thinking this a little. Use a non-blocking accept or a native accept with a timeout within a conditional loop. Add a mutex lock and it's thread safe. You can also use a native select and accept when new connection arrive. Set a timeout and a conditional loop for the select.

Related

Beast websocket idiomatic shutdown?

I have my C++ program. The main thread creates a new thread that is dedicated to only handling a websocket. This new thread reads and writes using for example boost beast's async_read() calls. It is much like https://www.boost.org/doc/libs/1_69_0/libs/beast/example/websocket/server/async/websocket_server_async.cpp where each async call gives rise to another async call.
But what is the idiomatic way to get the main thread to tell the websocket thread to shutdown given that there will likely always be some async read or write call outstanding like an async_read() idle waiting for the server to eventually send data. A shutdown would need to do something like cancel the remaining async_read() without introducing some kind of race condition where the read starts happening just before the cancel.
Use boost::asio::post to post a lambda to the io_context (using the appropriate strand if necessary) which calls cancel on the underlying basic_socket. Pending operations will complete immediately with boost::asio::error::operation_aborted. Inside your completion handler you can check basic_socket::is_open to know whether or not you should attempt new asynchronous calls.

Are Asio internal threads transparent to the users?

From the documentation, most Asio classes are NOT thread-safe. So I wonder is it safe for a user thread to access an object in async operation?
For example, if a socket is async connecting:
asio::async_connect(socket, endpoint_iterator, handler);
I suppose there will be an Asio internal thread (e.g. one runs io_service.run()) to do something on socket (No?). Is it safe to call socket.close() before the async_connect finishes (for timeout for example)? Will it race with any Asio internal thread?
Asio completely hides system dependent threads (pthreads, windows threads).
It does not matter which thread is handling your code, what does matter is the ioservice.
No async code is executed at all of you do not call ioservice.run().
I hope this is of some help.

How to execute async operations sequentially with c++ boost::asio?

I would like to have a way to add async tasks form multiple threads and execute them sequentially in a c++ boost::asio application.
Update: I would like to make a server-to-server communication with only one persistent socket between them and I need to sequence the multiple requests trough it. It needs to keep the incoming request in a queue, fire the top one / wait for it response and pick up the next. I'm trying to avoid using zeromq because it needs a dedicated thread.
Update2: Ok, Here is with what I ended up: The concurrent worker threads are "queued" for the use of the server-to-server socket with a simple mutex. The communication is blocking write/wait for response/read then release the mutex. Simple isn't it :)
From the ASIO documentation:
Asynchronous completion handlers will only be called from threads that
are currently calling io_service::run().
If you're already calling io_service::run() from multiple threads, you can wrap your async calls in an io_service::strand as described here.
Not sure if I understand you correctly either, but what's wrong with the approach in the client chat example? Messages are posted to the io_service thread, queued while a write is in progress and popped/sent in the write completion handler. If more messages were added in the meantime, the write handler launches the next async write.
Based on your comment to Sean, I also don't understand the benefit of having multiple threads calling io_service::run since you can only execute one async_write/async_read on one persistent socket at a time i.e. you can only call async_write again once the handler has returned? The number of calling threads might require you to lock the queue with a mutex though.
AFAICT the benefit of having multiple threads calling io_service::run is to increase the scalability of a server that is serving multiple requests simultaneously.

interrupting boost::asio::async_receive_from from another thread

I am reading multicast input using async_receive_from. So the idea is that when I detect a gap, I will notify another helper thread to request/get the gap filling messages. While this is in the works the main thread will continue to receive and queue any incoming messages. This part I can implement. The other thread can use waitforsingleobject and I can pass it the details through shared memory and notify an event to wake it up.
But once it completes it task, how do I get the helper thread to interrupt the async_receive_from in the initiating thread? And when it comes up out of the the read it knows who interrupted so it will then know what to do next?
Why are you using shared memory between threads?
That aside, the mechanism you should use for executing something in the context of the io_service which is managing the socket is post(). You can post any arbitrary event to the io_service, and it will execute in that context. Quite easy really... Because you are calling async_receive_from, it's not blocking, i.e. the io_service can dispatch other events, which is why the post will work.

Interrupt boost::asio synchronous read?

I'm using asio synchronous sockets to read data over TCP from a background thread. This is encapsulated in a "server" class.
However, I want the thread to exit when the destructor of this class is called.
The problem is that a call to any of the read functions does block, so the thread cannot be easily terminated. In Win32 there is an API for that: WaitForMultipleObjects which would do exactly what I want.
How would I achieve a similar effect with boost?
In our application, we set the "terminating" condition, and then use a self-connection to the port that the thread is listening on so it wakes up, notes the terminate condition and terminate.
You could also check the boost implementation - if they are only doing a plain read on the socket (i.e., not using something like WaitForMultipleObjects internally themselves) then you can probably conclude that there isn't anything to simply and cleanly unblock the thread. If they are waiting on multiple objects (or a completion port) you could dig around to see if the ability to wake blocking thread is exposed to the outside.
Finally, you could kill the thread - but you'll have to go outside of boost to do this, and understand the consequences, such as dangling or leaked resources. If you are shutting down, this may not be a concern, depending on what else that thread was doing.
I have found no easy way to do this. Supposedly, there are ways to cancel win32 IOCP, but it doesn't work well on windows XP. MS did fix it for windows vista and 7. The recommended approach to cancel asio async_read or async_write is to close the socket.
[destructor] note that we want to teardown
[destructor] close the socket
[destructor] wait for completion handlers
[completion] if tearing down and we just failed because the socket closed, notify the destructor that the completion handlers are done.
[completion] return immediately.
Be careful if you choose to implement this. Closing the socket is pretty straight forward. 'wait for completion handlers' however is huge understatment. There are several subtle corner cases and race conditions that could occur when the server's thread and its destructor interact.
This was subtle enough that we build a completion wrapper (similar to io_service::strand just to handle synchronously canceling all pending completion callbacks.
Best way is to create a socketpair(), (whatever that is in boost::asio parlance), add the reader end to the event loop, then shut the writer end down. You'll be woken up immediately with an eof event on that socket.
The thread must then voluntarily shut itself down.
The spawner of the thread should in its destructor, have the following:
~object()
{
shutdown_queue.shutdown(); // ask thread to shut down
thread.join(); // wait until it does
}
boost::system::error_code _error_code;
client_socket_->shutdown(client_socket_->shutdown_both, _error_code);
Above code help me close sync read immediately.
Use socket.cancel(); to end all current asynchronous operations that are blocking on a socket. Client sockets might need to be killed in a loop. I've never had to shut the server down this way, but you can use shared_from_this() and run cancel()/close() in a loop similarly to how the boost chat example async_writes to all client.