Boost logo

Boost :

From: Giovanni P. Deretta (gpderetta_at_[hidden])
Date: 2006-02-08 11:21:29


Christopher Kohlhoff wrote:
>>Yes this is thread unsafe. To make it thread safe, you need to
>>lock the list (or at least the objects involved) to protect
>>the swap.
>
>
> This, for me, is the killer. The motivation for move is to avoid
> expensive copying of "heavy" objects. Using locking to do the
> move is probably worse :)
>

As i said, i see, in this case, move as a correctness issue than an
optimization.
I do not see how you can avoid locking if you are going for intrusive
refcounting. For example, thread A creates a stream_socket and register
it in a demuxer. The demuxer might be shared between threads so it needs
to lock the list mutex to insert it in the queue. Then thread A might
destroy the socket at any time, so it need to relock the queue to remove
the socket. Am i missing something?

> I think there aren't sufficiently common use cases for
> movability to justify the costs. In my experience with asio I
> have not yet come across a real life situation where I would
> benefit from move, so it was really just a "wouldn't it be cool
> if..." sort of idea. The use cases are probably even more
> limited if you consider that what some people really want is
> copying and reference counting.
>

I have (*) one use case that would really benefit if asio moved its
callback instead of copying it. As the callback owns the socket, it
would need the socket to be movable, or at least swappable. And no, i
do not think it is a wouldn't be just "a cool thing"... it is obvious
from asio examples that support for moving (with support from bind of
course :) ) an auto pointer would be obviate the need of a shared_ptr. A
movable socket wouldn't even need dynamic allocation.

> It's worth noting that locking the list mutex may also be
> required to implement swap. But since locking a mutex can throw
> an exception, you now have a swap() that can throw. IMHO, to
> avoid nasty surprises having no swap() is better than having a
> throwing swap().
>

Yes, locking is required for swap too if you use ref counting.
I do not see how and why locking a mutex could trow? Boost::thread
mutexes do not throw. Pthread mutex fail only while trying to relock a
non recursive mutex (a precondition violation) or an uninitialized mutex
(another precondition violation).
Btw, you could use a lock free list (not that i know how to use it :) ).

>
>>Ah, btw, at least on posix systems, file descriptors are
>>guaranteed to be allocated contiguously. So you could create a
>>vector as big as the hightest fd, store the list of operations
>>in it and use the socket_impl as a key for an O(1) lookup in
>>the vector.
>
>
> Even for systems where this is true, it is only true for the
> whole process, not a single asio::demuxer object. You might have
> one demuxer per socket, in which case most of the vector is
> wasted.

Sure, but the highest socket value seen by a demuxer is not very high
(in the order of MAX_OPEN on sane systems). So the space wasted for a
not full demuxer is not much, and probably not much higher than keeping
a list with pointers to siblings. Most applications will have
approximately of one demux per thread (And one thread per cpu). The one
demuxer per socket could be special cased.

(*) Well, not working code now, still experimenting on it. I can work
around non having move by using copying, but it requires dynamic
allocation and ref counting.

-- 
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