Boost logo

Boost :

From: Christopher Kohlhoff (chris_at_[hidden])
Date: 2006-02-09 08:32:40


Hi Giovanni,

--- "Giovanni P. Deretta" <gpderetta_at_[hidden]> wrote:
> As i said, i see, in this case, move as a correctness issue
> than an optimization.

Can you explain what you mean by correctness?

Today I was pondering move (and swap) as a general design idea,
and I suspect that a good rule of thumb might be that they are
appropriate on value-type classes that have "heavy"
implementations, and particularly where copying may throw.

They do not seem appropriate operations for a non-value-type
class which has identity, since to me the address of the
object is part of its identity.

I do believe the usual motivation for move is as a performance
optimisation, to construct the target object with minimum
expense, e.g. see:

http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1377.htm

If it is not possible to implement move efficiently, then I
think it should not be there at all, otherwise it could lead to
unpleasant surprises.

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

But this locking is currently only needed when the socket object
is constructed or destroyed, which are not usually common
operations. Moving is something that could occur quite a lot.

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

The callbacks are an example of why I think a move operation
would have limited application. Move support can only be used if
there is just one chain of asynchronous operations associated
with the object. As soon as there is a second chain (e.g.
running an async_wait on a timer while you do an async_read, or
doing an async_read and async_write at the same time) the move
support becomes useless.

> I do not see how and why locking a mutex could trow?
> Boost::thread mutexes do not throw.

I see that it does not, but perhaps it should :) On Windows 2000
or earlier the EnterCriticalSection function can fail in low
memory situations. This is not handled at all in the
boost::mutex class as far as I can see.

> Btw, you could use a lock free list (not that i know how to
> use it :)).

I would categorise this as the "difficult" bit of "difficult and
inefficient" :)

Seriously though, the more I think about move the more problems
and limitations I see it creating for the implementation. Some
more examples:

- An implementation that stores state direct in the socket
  object may have pointers to that state in other data
  structures. All these would need to be tracked and updated if
  a move occurred.

- The data structures used by epoll and kqueue can contain a
  pointer to user data. For efficiency, this could (and probably
  should) point directly to the state that is embedded in the
  socket object. This pointer can only be updated via a system
  call.

This discussion has actually been quite helpful for me in
confirming why the sockets should not support move and swap...
Sorry :)

> Sure, but the highest socket value seen by a demuxer is not
> very high (in the order of MAX_OPEN on sane systems).

Hmmm, I dunno. I have used asio in servers that support more
than 50000 concurrent connections. That's potentially a lot of
wasted space!

Cheers,
Chris


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