Boost logo

Boost :

From: William Kempf (sirwillard_at_[hidden])
Date: 2000-08-09 11:27:10


--- In boost_at_[hidden], Kevlin Henney <kevlin_at_c...> wrote:
> In message <20000809155449.7867.qmail_at_w...>, Dietmar
> Kuehl <dietmar_kuehl_at_y...> writes
> >--- Kevlin Henney <kevlin_at_c...> wrote:
> >[lots on a generic approach]
> >
> >This is basically what I was looking for all the time. The only
reason
> >to write up this thin wrapper to pthreads was to show that
pthreads do
> >no impose any restriction on whatever interface we choose with
respect
> >to thread creation.
>
> Yes, I'd agree, esp as pthreads represent many of the common
concepts.
> If we can come up with a model that is easily implementable on top
of
> pthreads and Win32 I think that covers the most common requirement.
> There are threading models out there that are completely alien and
would
> not work easily (Mucos, IIRC, has something that is fairly
unwrappable
> in this respect).
>
> >> I'm happy to work out a strawman doc based on this idea and
building
> >> on Dietmar's definition's doc, if anyone's interested.
> >
> >I would greately appreciate if I wouldn't be required to write
> >everything :-) However, I can offer support on this, be it in form
of
> >ideas with respect to requirements, reviews, htmlization of text,
etc.
>
> That's cool. I'm out of the country from first thing Friday for a
week,
> and probably out of email reach. I guess the bright side of that is
that
> I will have more time to work on the doc :->

I'm very interested to read your approach. Currently, I think
a "generic" approach to concepts such as a mutex is a mistake.
There's no "type" to generalize on here, only traits. Traits work
great with template classes, but I'm not sure the traits we're
discussing here will easily lend themselves to a traits class here.
A generative programming approach would work for all of this, but
this seems overly complicated for something so simple. In the end
you wind up with multiple types being coded any way, you've just used
complicated coding techniques to do it. Simple classes could have
been used instead, resulting in identical functionality and a simpler
interface.

Let me list the points I think we're debating here:

recursion
process shared
timed/try lock

The recursion would be simple to implement in a traits class since a
mutex of either type can be used as the basis for a mutex of the
other. Process shared isn't so simple. An allocator type might work
here, but the code required for this would be just as easy to add in
the constructor. The only thing achieved by using an allocator type
would be to allow for other refinements beyond process shared... but
I'm not sure what other refinements you could possibly want here.
The timed/try lock becomes the clincher on why I don't think traits
will cut it. If the underlying implementation doesn't support one or
the other it will be impossible to implement as a traits class. An
allocator could decide whether or not the implementation has such
functionality, but that seems like a strange thing to do. Further,
the concrete instantiation will still have to either include a
timed/try lock or not in the interface, regardless of the type wanted.

The approach I'd take here would be to have 2 class types,
named_mutex and mutex. One or the other (or both) of timed/try locks
should be required for these, as they should not effect over all
performance or useage within the implementation, yet are needed for
many uses. I'd prefer to just settle on always being recursive, but
this could easily be dealt with by a parameter passed to the
constructor. (Actually, process shared could be handled in the same
manner, I seperated this into two classes only because it makes a
clearer seperation of the types.)

BTW, I prefer recursive after my own experience using both. I don't
find that recursive mutexes obscure the code in any way, while they
make designs such as the following simple:

class FooBar
{
private:
   int a;
   mutex mx;

public:
   FooBar() : a(0) { }

   int foo()
   {
      mutex::sentry lock(mx);
      a += 10;
      return bar();
   }
   int bar()
   {
      mutex::sentry lock(mx);
      a -= 5;
      return a;
   }
};

This is a gross over simplification. It's not obvious here why foo
must call bar. However, it should still illustrate the point. When
internal synchronization is used within an object it's often required
that we call other member functions that would result in a need for
recursive locking. The work arounds required to write FooBar above
with a non-recursive mutex are quite ugly, IMHO, and definately
result in code bloat, maintenance headaches, and less readable code.

William Kempf


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