-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Description
In my own ASIO based network libraries I spent days trying to track down a race condition and finally came across the following post:
https://stackoverflow.com/questions/36016135/asioasync-write-and-strand
That post informed me that my use of strands was only protecting the callback and not the invocation of the ASIO object methods. I see that same misuse of strands in websocketpp.
Example:
This was my initial understanding on how to use strands as you only need to wrap the callback:
if (config::enable_multithreading) {
lib::asio::async_connect(
tcon->get_raw_socket(),
iterator,
tcon->get_strand()->wrap(lib::bind(
&type::handle_connect,
this,
tcon,
con_timer,
callback,
lib::placeholders::_1
))
);
} else {
lib::asio::async_connect(
tcon->get_raw_socket(),
iterator,
lib::bind(
&type::handle_connect,
this,
tcon,
con_timer,
callback,
lib::placeholders::_1
)
);
}
When in reality you also need to protect the call to async_connect()
as it calls socket_.async_connect()
and socket_.close()
under the hood. Therefore in order to be safe we would actually need to do something like:
if (config::enable_multithreading) {
lib::asio::dispatch(tcon->get_strand()->wrap([this, tcon, iterator, con_timer, callback]{
lib::asio::async_connect(
tcon->get_raw_socket(),
iterator,
tcon->get_strand()->wrap(lib::bind(
&type::handle_connect,
this,
tcon,
con_timer,
callback,
lib::placeholders::_1
))
);
}));
} else {
lib::asio::async_connect(
tcon->get_raw_socket(),
iterator,
lib::bind(
&type::handle_connect,
this,
tcon,
con_timer,
callback,
lib::placeholders::_1
)
);
}
This of course would have to be done for all ASIO objects (ie sockets, timers, etc)