-
Notifications
You must be signed in to change notification settings - Fork 639
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
strand/executor issue #1589
Comments
Yes, remove |
Thanks for your fast reply. And what about the following calls? m_WebSocket.async_accept(boost::asio::bind_executor(m_Strand, std::bind(&WebSession::OnAccept, shared_from_this(), std::placeholders::_1))); m_WebSocket.async_read(m_Buffer, boost::asio::bind_executor(m_Strand, std::bind(&WebSession::OnRead, shared_from_this(), std::placeholders::_1, std::placeholders::_2))); m_WebSocket.async_write(m_Buffer.data(), boost::asio::bind_executor(m_Strand, std::bind(&WebSession::OnWrite, shared_from_this(), std::placeholders::_1, std::placeholders::_2))); |
By constructing the websocket with the strand, you do not need to call See also: |
Ok, that solved it. Thanks again. |
What about |
Use |
|
You have to use a NextLayer that names the strand instead of the polymorphic executor, something like:
|
Thanks, so in ssl context smth like
|
Yes just like that |
Thanks |
@vinniefalco https://wandbox.org/permlink/CtsYIKpNIjelFNUw Will the use of strand executor make possible to concurrently call async_write from several threads, or is a queue necessary? |
You need a queue. See: https://github.com/boostorg/beast/blob/develop/example/websocket/server/chat-multi/websocket_session.cpp#L102 |
Thanks, @vinniefalco Right now I am using an atomic write counter with the read-modify-write operation to prevent race condition in call async_write from multiple threads. And as a queue I use boost::asio - in case the writing is already in progress, I just call the boost::post. |
The queue is protected because it is only accessed from the strand: |
Sorry for the stupid question, but if post to strand protect Why can't we just do something like this:
|
In your code, |
Thanks! |
@vinniefalco sorry for disturbing you again... We were also using an algorithm with atomics to try to fix the problem with multiple async calls, we've found your comment recently and wanted to give it a try. While trying to implement this I got very confused with the Before 1.70.0 we were creating the strands explicitly, just like OP did. Then we updated to 1.70.0 and did the changes to make it work: here is a discussion regarding this. So let's start from the beginning, a strand object is(according to the official docs):
All clear. Now before 1.70.0 we were creating the strands explicit: ws(std::move(socket(io_context)));
strand(io_context); And when we wanted to use it, we would pass the strand to the async call: ws.async_accept(
boost::asio::bind_executor(
strand, std::bind(&WebSession::on_accept, shared_from_this(), std::placeholders::_1)
)
); This gave us the freedom to use multiple strands on the same Now in boost::asio::ip::tcp::socket socket( ::boost::asio::make_strand( io_context ) );
boost::beast::tcp_stream stream(::std::move(socket));
::boost::beast::ssl_stream<::boost::beast::tcp_stream> ssl_stream(::std::move(stream));
::boost::beast::websocket::stream<
::boost::beast::ssl_stream<::boost::beast::tcp_stream>>
ws(::std::move(ssl_stream)); And calling async methods like this: ws.async_write( boost::asio::buffer( "Message"),
std::bind( &ws_server::on_write_websocket, this, message_ptr,
std::placeholders::_1,
std::placeholders::_2 ) ); All clear, but after reading this issue I got a little bit confused. Notice that I have declared the ::boost::beast::websocket::stream<
::boost::beast::ssl_stream<::boost::beast::tcp_stream>>
ws(::std::move(ssl_stream)); Not like you said:
beast::websocket::stream<
asio::ip::tcp::basic_socket<
asio::strand<net::io_context::executor_type>>> ws; Does this mean that we are not using strand, even if we did create the socket using On which completion handlers does that strand apply(the one we created with Is this a valid case: to use read and write strands? I'm asking this because I see it as a performance improvement to use two strands, the reads and writes are separated and can be done concurrently without any problem... What is the purpose of LE: I forgot to mention, we are using using tcp_stream = basic_stream<
net::ip::tcp,
net::executor,
unlimited_rate_policy>; To apply the strand layer we should do something like this: ? using tcp_stream_strand =
basic_stream<net::ip::tcp,
boost::asio::strand<boost::asio::io_context::executor_type>,
unlimited_rate_policy> Thanks 😄 |
Nope, that will cause undefined behavior, because two different threads could touch the The purpose of putting the strand executor on the |
Hey @vinniefalco,
I did replace using tcp_stream_strand = ::boost::beast::basic_stream<::boost::asio::ip::tcp,
boost::asio::strand<boost::asio::io_context::executor_type>,
::boost::beast::unlimited_rate_policy>; But I got an error and I do not know how to fix it: /celibs/boost_1_71_0/boost/beast/core/impl/basic_stream.hpp:38:17: error: no matching function for call to 'boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::strand<boost::asio::io_context::executor_type> >::basic_stream_socket(boost::asio::basic_stream_socket<boost::asio::ip::tcp>)'
38 | , timer(ex()) Here's the source code, it's only 3 lines in main: https://godbolt.org/z/UwLdY1 using tcp_stream_strand = ::boost::beast::basic_stream<::boost::asio::ip::tcp,
boost::asio::strand<boost::asio::io_context::executor_type>,
::boost::beast::unlimited_rate_policy>;
int main()
{
boost::asio::io_context ioc;
boost::asio::ip::tcp::socket socket(::boost::asio::make_strand(ioc));
tcp_stream_strand stream(::std::move(socket)); // here is the error
// boost::beast::tcp_stream stream(::std::move(socket)); // This works
return 0;
} I do not understand why it doesn't work... What am I doing wrong? |
Should read:
I don't think that's your problem though, I'm working on it. |
I see the problem. You are attempting to use this constructor overload: However, this overload is only available if the following condition is met:
Here, Executor1 is If you want to use the concrete type in the
|
Thanks, that works 😄 Today I've reread your previous answer again and there are some things that I thought I knew how they work in boost asio... I though that the purpose of the But the If I'm using a It's like when you call Otherwise there would be two calls on the
Can you confirm this? Or the async calls do not modify the Thank you again, really. You've helped me alot. 😄 |
Perfect. Thanks. This is something that I didn't knew 😄 |
@vinniefalco , apologize for spamming stupid question here, I have dummy broadcast ws server here, but my first intention is when the server successfully broadcast write data then the server must read client request again. How to avoid soft_mutex try_lock assertion when async_read on my gist .. thanks |
Please open a new issue, thanks ! |
Hi,
my WebSession class looked like this:
With the latest version boost 1.70 the code doesn't compile anymore at the following line
m_Strand(m_WebSocket.get_executor())
error C2664: 'boost::asio::strandboost::asio::io_context::executor_type::strand(boost::asio::strandboost::asio::io_context::executor_type &&) noexcept': cannot convert argument 1 from 'boost::asio::executor' to 'const boost::asio::io_context::executor_type &'
note: Reason: cannot convert from 'boost::asio::executor' to 'const boost::asio::io_context::executor_type'
note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Any idea how to fix this?
The text was updated successfully, but these errors were encountered: