Boost logo

Boost :

From: William E. Kempf (williamkempf_at_[hidden])
Date: 2002-08-06 09:57:11


----- Original Message -----
From: "Peter Dimov" <pdimov_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Tuesday, August 06, 2002 7:17 AM
Subject: Re: [boost] Re: Re: Threads & Exceptions

> From: "Moore, Dave" <dmoore_at_[hidden]>
> >
> > Eric Woodruff:
> >
> > Personally, I don't think advanced_thread should compose a boost::thread
> or
> > derive from it. boost::thread is fairly impotent. If the advanced_thread
> was
> > named asyncronous_function_adapter, boost::thread would be depreciated,
as
> I
> > said earlier. (Of course, for the platform neutrality,
> > asyncronous_function_adapter would have to dervive from a protected
> private
> > base class where the platform-specific code would reside.)
> >
> > However, removing the non-templated (publically accessible) base type
> would
> > probably introduce complexity in the thread pool (which would again need
> to
> > be renamed if the thread was thrown out). I suggest instead putting
> > boost::thread in a sub namespace and frowning at its use.
> >
> > **Reply**
> >
> > Yes, but there are of course many ways to use threads in application
> designs
> > besides asynchronous function calls. Asynch function calls are a useful
> > mechanism, but aren't a universal replacement for a general purpose
> > threading class.
>
> I'm with Eric here. Async function call in the advanced_thread sense is a
> proper superset of the general purpose threading class (boost::thread
> sense.) That is,
>
> template<class R> class thread
> {
> public:
> thread(function0<R> f);
> R join();
> };
>
> completely subsumes thread<void>, which is what boost::thread currently
is.
>
> Roll-your-own thread<R> is possible, but I definitely don't agree with its
> "triviality",

void foo(int& res)
{
   res = 10;
}

int result;

boost::thread thread(boost::bind(&foo, boost::ref(result))); // warning,
done from memory and likely wrong
thread.join();
std::cout << result << std::endl;

I'd call this trivial. Adding a value return to boost::function would only
allow illimination of two lines above (the declaration of "result" and a
merging of the join() call and the cout line), neither of which add anything
to the clarity of the code, and in fact would make the code less readable,
IMHO. This design also puts some requirements on the return type, as I've
said before. The only thing this design has going for it is that users are
generally more comfortable with return values instead of out values. For
these reasons I purposefully chose the design that I did. I still think it
was the correct choice, but I'm open to debate.

> especially when a thread group (performing a computation in
> parallel) needs to be joined and the results combined.

I don't see how the above implementation is any less trivial even in this
case.

> (Having threads that
> play with standard library containers could help, too, but I digress.)

Meaning removal of the noncopyable semantics?

> Now, if you accept thread<R>, the exception handling kind of follows
> naturally. It is a postcondition of
>
> R join();
>
> that it returns the return value of the expression 'f()'. If f() throws,
> there is no return value, and therefore join() must also throw; it cannot
> return.

I don't agree. Again, in most cases if an exception occurs on a thread (and
is not handled in that context) there's little that can be done except
terminate. If the thread does handle the exception I'd think it would be
more natural to return an error condition here in most cases. It would be
the choice of the thread calling join() whether or not such an error would
be considered exceptional or not, and so it should have the responsibility
of interpreting the error and throwing an exception.

> The enumerated exception list is questionable, though. I'd specify join()
to
> throw an implementation-defined exception when f() throws. With compiler
> magic, it can even be a copy of the real thing. Without, well, it can at
> least preserve std::exception::what().

Another issue here is, again, how this ties in with current exception
semantics. Though not necessarily a good application design, current
threading libraries allow you to join the "main" thread (and the best we
could do is prohibit this in documentation). As long as you can join the
main thread we'll have to change the standards required behavior of
propogating an exception out of main(), and that would be something tricky
to implement and obviously all implementations would be non-portable.

Bill Kempf


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