Boost logo

Boost :

From: williamkempf_at_[hidden]
Date: 2001-05-23 13:32:19


--- In boost_at_y..., Beman Dawes <bdawes_at_a...> wrote:
> At 09:38 AM 5/23/2001, williamkempf_at_h... wrote:
>
> >> it. There is nothing wrong with a mutex.
> >
> >No, but there is something wrong with a mutex being used at this
> >granularity.
> >
> >> Think about needs for counters of various totals to be reported
by
> >several
> >> worker threads. Each thread would keep its own local totals (so
> >they could
> >> be updated efficiently without locking), but then just before
> >closing down
> >> would update the shared thread_safe_int_least32_t program
totals.
> >No
> >> particular efficiency issue there, just safety.
> >
> >That's simple addition, not a full range of integral operations,
so
> >it's not much of an example of the need for a full
> >thread_safe_int_least32_t. This particular example would best be
> >served by "traditional" synchronization, i.e. you'd roll the
> >synchronization yourself. Why? Well, it's just to simple of an
> >example to be worth addressing in a library.
>
> It may be simple, but who wants to write even a simple class every
time
> such a common need arises? And test it, and document it, and so
on. I'd
> rather have it (and other common usage patterns) as part of a
library.

As has been pointed out before, some patterns are best left as
patterns and not codified into classes. The monitor pattern is a
good example of this. Singletons are another good example. This one
is just one more example.

> > For instance, it's
> >quite possible that there will be multiple such totals that need
to
> >be updated and it would be better to use a single mutex for all of
> >them then to use a mutex per total as would be done by a library
> >solution.
>
> But that is more error prone (if the mutex is manipulated manually,
rather
> than wrapped in a class),

I never suggested manipulating the mutex manually. I'd expect the
totals to be wrapped up into an appropriately designed class which
handles the synchronization in the most efficient manner possible.

> is slower (if there are multiple threads
> contending for otherwise unrelated counters),

This is where you need to look at the bigger picture. As I said, if
multiple counters are going to be modified using a single mutex is
going to be faster than using a mutex per counter. What's needed all
depends on the usage requirements of a given application. A library
can't even begin to guess what level of granularity is best, and so
it shouldn't try to.

> and in general making an
> assumption about what a programmer wants to optimize.

Actually, it makes no assumptions. A thread_safe_int_least32_t on
the other hand makes several assumptions on what to optimize, which
is precisely what I was pointing out here.

> Maybe the programmer
> wants to favor programming effort, safety, and speed rather than
mutex
> memory space.

A thread_safe_int_least32_t addresses effort, but it does not address
safety or speed. And I never even considered mutex memory space.
 
> >> Now of course there could be an application mutex, but why
bother?
> >It just
> >> opens up the possibility of misuse. A thread_safe_int_least32_t
> >would wrap
> >> the functionality up in a nice safe package that would be very
hard
> >to
> >> misuse. That's what C++ classes are all about.
> >
> >The reason to bother is to attain the optimal granularity of lock
> >(and an "application mutex" might not fit that bill either). A
> >threading library can't predict what level of granularity is
optimal
> >since it's going to depend on the application, so such a type just
> >isn't appropriate.
> >
> >Beyond that, there's a severe problem with a
> >thread_safe_int_least32_t that behaves as an int. The level of
> >granularity of such a lock can actually lead to errors in usage.
For
> >example:
> >
> >thread_safe_int_least32_t i = 10;
> >i = (i + 2) / 2;
> >
> >The above expression should be executed "atomically" (as in no
other
> >thread can change the value of 'i' while the expression is being
> >evaluated) but it is not. The internal mutex is only locked
during
> >the call to a single operation, so it's possible for another
thread
> >to interrupt and change the value of 'i' in between the '+' and
> >the '/'. It can even interrupt before the assignment! This is
why
> >atomic_t has very specific functions that can be called such as
inc()
> >and dec() and doesn't have overloaded operators such as '++'
and '--'.
>
> So reduce it to functions which can be safely provided.
>
> The point is to give programmers a nice palette of mid and hi level
tools,
> not just the very low level ones. Jens Maurer's bounded queue was
a good
> example.

The bounded queue can't compare to a thread_safe_int_least32_t in
this case, IMHO. The queue is a tight design that can be easily
reused efficiently and safely for a large number of applications,
while the thread_safe_int_least32_t makes so many assumptions as to
make it's applicability very small with very little added benefit.

Bill Kempf


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