$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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