Boost logo

Boost :

From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2021-12-29 11:22:53


Hi everyone,
Back in September Dmitry offered the following alternative to the to the
asynchronous TCP echo server example (
https://www.boost.org/doc/libs/1_77_0/doc/html/boost_asio/example/cpp11/echo/async_tcp_echo_server.cpp)
that uses a unique_ptr instead of shared_ptr for managing the lifetime of
the session (the socket and the buffer):

wt., 21 wrz 2021 o 17:22 Дмитрий Архипов via Boost <boost_at_[hidden]>
napisał(a):

> I haven't tested it, but this should probably work:
>
> class session {
> public:
> session(tcp::socket socket)
> : session(std::make_unique<session_impl>(std::move(socket)))
> {}
>
> void start() { do_read(); }
>
> private:
> session(std::unique_ptr<session_impl> impl) : impl_(std::move(impl)) {}
>
> void do_read()
> {
> auto& impl = *impl_;
> impl.socket.async_read_some(
> boost::asio::buffer(impl.data, max_length),
> [impl = std::move(impl_)](boost::system::error_code ec,
> std::size_t length) mutable {
> if (ec) { return; }
> session(std::move(impl)).do_write(length);
> });
> }
>
> void do_write(std::size_t length) { ... }
>
> auto constexpr max_length = 1024;
> struct session_impl {
> session_impl(tcp::socket socket) : socket_(std::move(socket)) {}
> tcp::socket socket_;
> char data_[max_length];
> };
> };
>
> ...
>
> session(std::move(socket)).start();
>

The idea here is that the last completion handler to be installed is
responsible for calling the destructor. But this can only work under the
assumption that the ASIO framework guarantees that the completion handler
is destroyed after all the preceding operations have finished. Otherwise we
can envision the situation where the destructor in the handler is called
but the previous operation is still trying to access the socket.

Under normal circumstances, it should be quite obvious that the previous
operation is finished before the handler is invoked and destroyed. But it
is not that obvious when we add the operation cancellation into the
picture. I could imagine an implementation where an operation receives a
cancellation request, it already knows that it will not be calling the
completion handler, so it destroys the handler, and then does its own
cleanup.

So, my question is: does ASIO give a guarantee that it destroys the
completion handler after the preceding operations have finished?

Regards,
&rzej;


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk