Boost logo

Boost :

From: Giovanni P. Deretta (gpderetta_at_[hidden])
Date: 2006-04-28 14:02:36


Hi Chris,
a couple of questions/notes (I do not have the time right now to
download the lastest version from the vault, so may be the docs already
have answers for those, but still...)

Christopher Kohlhoff wrote:
> * Renamed locking_dispatcher to strand.
>
> A strand is defined as a strictly sequential invocation of
> event handlers (i.e. no concurrent invocation). Use of strands
> allows execution of code in a multithreaded program without
> the need for explicit locking (e.g. using mutexes).
>
> Strands may be either implicit or explicit, as illustrated by
> the following alternative approaches:
>
> - Calling io_service::run() from only one thread means all
> event handlers execute in an implicit strand, due to the
> io_service's guarantee that handlers are only invoked from
> inside run().
>
> - Where there is a single chain of asynchronous operations
> associated with a connection (e.g. in a half duplex
> protocol implementation like HTTP) there is no possibility
> of concurrent execution of the handlers. This is an
> implicit strand.
>
> - An explicit strand is an instance of asio::strand. All
> event handler function objects need to be wrapped using
> asio::strand::wrap() or otherwise posted/dispatched
> through the asio::strand object.
>

Does asio always grab a mutex before invoking a strand protected
handler, or it guarantees that the same strand is run on the same thread
and thus have automatic serialization? Just an implementation detail, i
know, but i'm curious.

> * Handler-based custom memory allocation.
>
> Many asynchronous operations need to allocate an object to
> store state associated with the operation. For example, the
> Win32 implementation needs OVERLAPPED-derived objects to pass
> to Win32 API functions.
>
> Furthermore, programs typically contain easily identifiable
> chains of asynchronous operations. A half duplex protocol
> implementation (e.g. an HTTP server) would have a single chain
> of operations per client (receives followed by sends). A full
> duplex protocol implementation would have two chains executing
> in parallel. Programs should be able to leverage this
> knowledge to reuse memory for all asynchronous operations in a
> chain.
>
> Given a copy of a user-defined Handler object h, if asio needs
> to allocate memory associated with that handler it will
> execute the code:
>
> void* pointer = asio_handler_allocate(size, &h);
>
> Similarly, to deallocate the memory it will execute:
>
> asio_handler_deallocate(pointer, &h);
>
> These functions are located using ADL. The asio library
> provides default implementations of the above functions in the
> global namespace:
>
> void* asio_handler_allocate(size_t, ...);
> void asio_handler_deallocate(void*, ...);
>
> which are implemented in terms of ::operator new() and
> ::operator delete() respectively.
>
> The implementation guarantees that the deallocation will occur
> before the associated handler is invoked, which means the
> memory is ready to be reused for any new asynchronous
> operations started by the handler.
>

I'm not sure if these functions are not enough (or at least have enough
parameters). They have no way to know alignment requirement of the
allocated object (and thus assume the worst), and the deallocator does
not have a size_t parameter (as operator delete has).
What about these signatures:

        template<typename T>
        T* asio_handler_allocate(size_t, handler_type&);

and

        template<typename T>
        void asio_handler_deallocate(size_t, handler_type&, T*);

> * Support for reference-counted buffers.
>
> The Const_Buffers and Mutable_Buffers concepts have been
> modified to allow reference counted buffers to be used. In
> particular:
>
> - The {Const|Mutable}_Buffers::iterator typedef and
> non-const begin()/end() functions have been removed from
> the concepts' requirements. Implementations of the
> concepts now need only provide const_iterator support, and
> do not need to allow in-place modification of the
> elements.
>
> - The asio implementation guarantees that at least one copy
> of the buffers object will be maintained for as long as
> the system may need access to the data.
>
> - The asio implementation explicitly converts the
> dereferenced const_iterator into mutable_buffer or
> const_buffer as needed.
>

Very good, but what about explicitly guaranteeing that *exactly* one
*live* (1) copy of the buffers object will be maintained?
I'm sure in practice asio already guarantees that, but specifying it
makes it possible to hold the buffer with an auto_ptr-like smart
pointer, without the overhead of a shared_ptr if it is not needed.

That's all for now... as soon as I have a little more time I hope to be
able to try the last version and finish my coroutine lib :)

Very good work.

(1) that is, if the object ever is copied, only the last copy is ever
used again. Other copies can only be destroyed.

-- 
Giovanni P. Deretta

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