Boost logo

Boost :

From: William Kempf (sirwillard_at_[hidden])
Date: 2000-08-31 08:52:17


--- In boost_at_[hidden], Dietmar Kuehl <dietmar_kuehl_at_y...> wrote:
> Hi,
> William Kempf wrote:
>
> > Possible interface:
>
> First of all, I'm in favour of such an interface using function on
an
> opaque type. A possible variation might be the use of traits-like
> approach: Since there is only one dimension of variation (the
> atomic type) it is not necessary to have the functions as non-member
> functions. Thus, something like this might be more in order:
>
> atomic_traits<atomic_t>::increment(val)
> atomic_traits<atomic_t>::decrement(val)
> ...

This implies that atomic_traits<> will operate on types other than
atomic_t. Not that I'm against this, I just want to understand the
motivation for this.

> > typedef ... atomic_t;
> > long increment(atomic_t& dest);
> > long decrement(atomic_t& dest);
>
> I can see uses for these three, eg. a referenced counted entity.
>
> > long add(atomic_t& dest, long value);
> > long add(atomic_t& dest, const atomic_t& value);
> > long exchange(atomic_t& dest, long value);
> > long exchange(long& value, const atomic_t& value); // Note 1
> > long compare_exchange(atomic_t& dest, long compare, long value);
>
> ... but I have no idea what this stuff might be used for. Unless
there
> are
> important uses of the more advanced features, I would prefer to
stick
> with the bare minimum of functionality which are atomic increment
> and decrement functions. If there are usage patterns for the other
> features, I would divide them into concepts: I can imagine
platforms to
> have native support for efficient increment and decrement but not
for
> the others. Requiring the more advanced features would unnecessarily
> burden these atomic integers.

I agree that you want to stick with the minimum functionality.
That's why multiplication etc. isn't included. As for why I think
these should be included...

add() allows for fancier reference counting where some times the ref-
count must be incremented/decremented by some multiple other than 1.
For example, to temporarily reduce the reference count to 0 and
return it later to the old value, such as might be done with a count
of the number of recursive locks on a thread when the Mutex needs to
be completely unlocked within the wait() of a ConditionVariable.

The exchange functions are used to get the value, for one thing ;).
Beyond this, it's used in cases where the counter is being used for
tracking a flag. For instance, check out the Win32 implementation
I've posted in the threads folder. I've used the Win32 native
equivalent InterlockedExchange() in a few places, both to atomically
check the value of a ref-count as well as to set/check the value of a
thread id in an atomic fashion. The compare_exchange() is more
obscure and I'd have to admit to having never used it myself.
However, I bet others can point out why it's needed, so I left it in
the list.
 
> Can you please outline where the other features are necessary?
>
> I assume it is a lost battle to bring up again that this stuff
seems to
> be at
> a too low level of abstraction for now: I still haven't seen the
high
> level
> entities which are implemented using these low-level features...

But you have, at least if you've looked at the Win32 code I've
posted. I think you can see from the discussion here that the
Monitor is the most flexible high level abstraction in use.
(Actually, CSP makes use of MessageQueue models, calling them
channels, instead... but building the MessageQueue will require a
Monitor.) A Monitor is just a pattern where you model an object to
have managed internal synchronization using a Mutex and one or more
ConditionVariables. On Win32 there is no such thing as a
ConditionVariable, so I had to model one using the lower level
primitives that Win32 does have available. For performance reasons I
used the Win32 API to do so, but I could have just as easily used our
low level models. In fact, doing so would reduce the amount of code
that needs to be ported when you move from platform to platform.

We're building a skyscraper out of tinker toys here. Once we've got
the skyscraper we may never use the tinker toys again, so they may
not be part of the final library. However, I think that these
primitives are too useful to ever eliminate, even if they are seldom
used because of higher level concepts. After all, they can be used
to model other high level concepts that might prove to be easier,
more efficient and safer than the first set of high level concepts we
design. Having a set of well defined, portable primitives will make
doing such higher level designs much easier.

Bill Kempf


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