1

According to the MSDN doc for closesocket:

"A Winsock client must never issue closesocket on s concurrently with another Winsock function call."

For example, what happens if an IO completion thread detects an error and closes the socket:

client_socket_.lowest_layer().close(ec);

while concurrently another thread is about to call:

async_write(client_socket_,...)

Could both of these calls hit their underlying closesocket() and WSASend() APIs, thus causing a potential crash?

I've seen these types of crashes in ordinary C++, but wasn't sure if Boost C++ had some kind of builtin mechanism to prevent it? If not, then do these calls require a scoped locked mutex etc.,..

Thanks.

vengy
  • 1,548
  • 10
  • 18

1 Answers1

1

If you use a strand¹ there's no real problem, though I'll submit that it's probably cleaner (much cleaner) to invoke shutdown() before/instead of close() in many scenarios.

Asio does requires you to synchronize access to the socket/stream objects (everything other than the documented thread-safe objects as io_context and strand, really). Strands fulfill the role traditionally held by critical sections.

¹ implicit or explicit, see Why do I need strand per connection when using boost::asio?

sehe
  • 374,641
  • 47
  • 450
  • 633
  • strands are a new concept for me, so I'll probably stick with a simple mutex: THREAD#1: boost::mutex::scoped_lock lock(mutex_); client_socket_.lowest_layer().close(); THREAD#2: boost::mutex::scoped_lock lock(mutex_); async_write(...) Thanks. – vengy May 06 '20 at 21:59
  • You can't stick with a simple mutex in many situations (for one thing you will not be able to hold one across handlers). Also, the point about implicit strands is that you may well not need locking at all. See the linked answer :) – sehe May 06 '20 at 22:07
  • True. I'll look into this example which uses the strands technique: https://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/example/http/server3/connection.hpp – vengy May 06 '20 at 22:35
  • 1
    Applying the strand bind_executor() works great now. No crashes due to concurrency! async_write(client_socket_.next_layer(),boost::asio::buffer(server_data_, bytes_transferred),boost::asio::bind_executor(strand_,boost::bind(&Bridge::handle_client_write,shared_from_this(),boost::asio::placeholders::error))); – vengy May 12 '20 at 21:03