Boost logo

Boost :

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


--- In boost_at_[hidden], "Borgerding, Mark A." <MarkAB_at_x> wrote:
>
>
> > -----Original Message-----
> > From: William Kempf [mailto:sirwillard_at_m...]
> ...
> >
> > Personally, to me the thread class should not be used as a base
> > class. I see a very distinct seperation of a "thread" and the
> > process that's run within the thread. A runnable class is
better,
> > but I don't care for it either. This imposes a class heirarchy
> > decision on all code that will use threads from that point on.
Any
> > time you can avoid a class heirarchy I think you've made the code
> > more reusable and easier to deal with. A "slot as thread proc"
> > approach will allow complete flexibility in design, including any
and
> > all designs that you'd do with base thread or runnable classes.
>
> Just because a thread is implemented via a base class does not mean
any
> absolute restrictions are imposed on a class hierarchy.

Oh, but they are. You can't create a thread with out a class
heirarchy. Yes, an adapter seems to do the same thing, but it
requires a class heirarchy. Further, with out careful thought to
your adapter you wind up writing adapters frequently. The one you
provide below, for example, puts an interface requirement onto the
types useable by requiring a Run() method. Slots (functors used as
callbacks, basically) eliminate most of the problems. Generic
adapters allow nearly any type of function to be called, including
member functions of specific objects. The types allowed as
parameters are also type safe and open ended thanks to further
generic adapters.

You also ignored my first protest... that the thread class be
seperated from the process that runs within the thread. They are two
seperate and distinct objects.

Further, the base class approach requires the use of virtual
functions, which adds overhead to our objects. I'd like to avoid
this.

> A subclass of the base thread class can be used as an adaptor (GoF)
to
> forward calls on to whatever object you give it at runtime.
>
> Example:
>
> class base_thread
> {
> protected:
> virtual int Run() = 0;
> };
>
> template <class T_Runnable>
> class adapter_thread : public base_thread
> {
> private:
> T_Runnable * m_pRunnable;
> virtual int Run() { return m_pRunnable->Run(); }
> };
>
>
> voila! You can create a adapter_thread<foo> where foo needs only to
provide
> an function with signature "int Run()".
> adapter_thread<foo> supplies the virtual function that base_thread
needs,
> and passes the call along to foo without requiring anything more
than a
> Run() function.
>
> The Run() function could be changed to something else -- maybe even
made a
> template parameter.
>
> My point is this:
> Using an abstract base class as the mechanism for implementing
threads is
> the most straightforward method. And it imposes no real
restrictions on
> what can be done (see above). If we start going off the deep end
with
> functors and such just to make things as generic as possible, we
will
> alienate the average programmer, for whom subclassing provides the
most
> easily understood (and most commonly used) approach.

Functors are not complicated. It's nearly essential that one
understand functors in order to use the STL algorithms. I hardly see
them as a detriment to learning for new users, especially since a
function pointer qualifies as a functor.

I think we're premature on this discussion, though. I agree with
others that the first emphasis needs to be on the synchronization
primitives. Because threads are going to exist in a lot of programs,
we need these to write portable and safe library code, even if we
never create a single thread ourselves.

William Kempf


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