-
I was updating my mqtt client code to 10.0.0 and realized that it's probably not safe to issue async_recv in the lambda that processes the async_recv for a long lived client, as shown in this basic use example: https://github.com/redboltz/async_mqtt/blob/10.0.0/example/ep_cb_mqtt_client.cpp My mqtt client maintains a persistent connection indefinitely. Won't this lead to deep linking of callbacks and an eventual fatal error? Do I need to add code to loop while connected and call async_recv only after a packet has been received? Or am I over thinking this and the library handles these issues. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 3 replies
-
Let me clarify your question: Are you asking whether invoking async_read within the async_recv callback could cause a stack overflow? |
Beta Was this translation helpful? Give feedback.
-
Yes, exactly. It looks like it would, so I changed my code to use a loop with lock and condition_variable to wait on the receive before issuing a new endpoint.async_recv. Basically, this:
Is this a good approach? |
Beta Was this translation helpful? Give feedback.
-
Short answer: Calling the next Detailed answer:
In contrast, The key question is whether See async_mqtt/include/async_mqtt/asio_bind/impl/endpoint_recv.hpp Lines 15 to 44 in 6f107e9 async_mqtt/include/async_mqtt/asio_bind/impl/endpoint_recv.ipp Lines 320 to 347 in 6f107e9 First, consider the dispatch phase: async_mqtt/include/async_mqtt/asio_bind/impl/endpoint_recv.ipp Lines 149 to 155 in 6f107e9 Then, the function calls async_mqtt/include/async_mqtt/asio_bind/impl/endpoint_recv.ipp Lines 156 to 172 in 6f107e9 If Next, consider the read phase: async_mqtt/include/async_mqtt/asio_bind/impl/endpoint_recv.ipp Lines 226 to 232 in 6f107e9 At this point, Thus, in both cases, the call stack is reset. Hence, calling the next |
Beta Was this translation helpful? Give feedback.
Short answer:
Calling the next
async_mqtt::endpoint::async_recv()
in the completion handler (e.g. callback) ofasync_mqtt::endpoint::async_recv()
is safe.Detailed answer:
dispatch()
andpost()
are different.dispatch()
executes the handler immediately if the caller is running in the same executor. Consequently, a recursivedispatch()
call can cause a stack overflow. See https://godbolt.org/z/1Thd73EvPIn contrast,
post()
simply adds the handler to the tail of the executor's internal queue, and the handler is later invoked viaioc.run()
, ensuring that the call stack is not increased. See https://godbolt.org/z/8nEcfe1zYThe key question is whether
endpoint::async_recv()
behaves likedispa…