Boost logo

Boost :

From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2021-09-22 14:39:07


wt., 21 wrz 2021 o 22:47 Richard Hodges via Boost <boost_at_[hidden]>
napisał(a):

> On Tue, 21 Sept 2021 at 17:22, Дмитрий Архипов via Boost <
> boost_at_[hidden]> wrote:
>
> > 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();
> >
> > вт, 21 сент. 2021 г. в 18:02, Andrzej Krzemienski via Boost
> > <boost_at_[hidden]>:
> > >
> > > wt., 21 wrz 2021 o 16:50 Vinnie Falco via Boost <boost_at_[hidden]
> >
> > > napisał(a):
> > >
> > > > On Tue, Sep 21, 2021 at 7:34 AM Andrzej Krzemienski via Boost
> > > > <boost_at_[hidden]> wrote:
> > > > > I am not trying to solve any specific problem. It just strikes me
> > that a
> > > > > shared_ptr is used in a demo example for the library. I was always
> > of the
> > > > > opinion that a shared_ptr is often abused as a way of doing an
> > ad-hoc GC.
> >
>
> Dear Andrzej,
>
> The use of shared_ptr in asio examples is largely an historic artefact from
> when the only completion type was only a function object, as in these
> examples.
>
> When using this style of asynchronous completion it is convenient to use
> some kind of reference-counted pointer to maintain the lifetime of IO
> objects such as sockets and their associated state, such as buffers. You
> don't *have* to use a reference-counting but you will need to ensure that
> the io objects and related buffers are not deleted while there are any
> asynchronous operations in progress against them. A shared_ptr happens to
> be the most convenient way of doing this when:
> - using continuation-passing style completion handlers, and
> - the lifetime of the io object is not deterministic.
>
> When using other styles of completion handling, such as the in-built
> coroutine support, reference counting can often become less important since
> code can be written in a "structured concurrency" style. In this way,
> asynchronous code can be laid out with the same structure as synchronous
> code. IO Object lifetimes then become governed by the coroutines that
> created them and are awaiting asynchronous operations against them.
>

Thank you for this insightful reply. My impression when looking at ASIO
examples is similar.
Either I decide to use function callbacks, and in this case I will use
reference counting (or apply a very clever trick), or I will use C++
coroutines.
In either case there will be an additional heap memory allocation required:
either manually by me, or indirectly by the coroutine machinery.

I wonder if heap allocation is a necessary consequence of asynchronous
computations, or is it only the choice of the interface in ASIO.

Regards,
&rzej;

>
>
> > > >
> > > > In theory it should work since the echo protocol is half-duplex. What
> > > > happens when you switch it to unique_ptr? Move-only handlers should
> > > > work, but it is possible that Chris missed a place that is still
> doing
> > > > a copy.
> > > >
> > >
> > > It breaks when I pass a callback (completion handler), for instance in:
> > >
> > > void do_read()
> > > {
> > > auto self(shared_from_this());
> > > socket_.async_read_some(boost::asio::buffer(data_, max_length),
> > > [this, *self*](boost::system::error_code ec, std::size_t
> length)
> > > {
> > > if (!ec)
> > > {
> > > do_write(length);
> > > }
> > > });
> > > }
> > >
> > > I would need to move the data inside the lambda capture, but if I do
> > > it, the subsequent call to socket_.async_read_some() is UB.
> > >
> > > In order for this to work, the function `async_read_some()` would have
> > > to pass the socket back to my handler after it has performed the read.
> > >
> > > Regards,
> > > &rzej;
> > >
> > > _______________________________________________
> > > Unsubscribe & other changes:
> > http://lists.boost.org/mailman/listinfo.cgi/boost
> >
> > _______________________________________________
> > Unsubscribe & other changes:
> > http://lists.boost.org/mailman/listinfo.cgi/boost
> >
>
> _______________________________________________
> Unsubscribe & other changes:
> http://lists.boost.org/mailman/listinfo.cgi/boost
>


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