Boost logo

Boost :

From: Beman Dawes (bdawes_at_[hidden])
Date: 2001-06-27 12:52:32


Bill Kempf wrote:

>Considering all of the discussion so far, I think this slightly
>modified interface is the best design so far:
>
> class thread : boost::noncopyable
> {
> public:
> thread(detail::threadproc proc); // Starts the thread
> ~thread(); // If not detached, detaches the thread
>
> // Considering that this type is noncopyable, these
> // operations are probably not necessary, but I'll
> // leave them in for the sake of discussion.
> bool operator==(const thread& other) const;
> bool operator!=(const thread& other) const;
>
> // To allow us to not need self(), at least for
> // comparison.
> bool is_current() const;
>
> bool is_alive() const;
>
> // Waits for the thread to finish and then calls detach()
> void join();
> // Seperates the object from the actual thread of execution
> // allowing the thread to just "evaporate" when finished
> // or when the main thread of execution terminates.
> void detach();
>
> // I have a feeling this one should go away with this
> // design, but again I'll leave it in for discussion.
> static void join_all();
>
> // These two can probably become free standing methods,
> // though I like the encapsulation.
> static void sleep(const xtime& xt);
> static void yield();
> };
>
>As it stands, this design is very viable, and is the best of what's
>been discussed.

It seems like a really good candidate to me, too, modulo possibly removing
members you talk about below.

> My concerns are:
>
>1) Will other operations that can be performed on threads create a
>very real need for a self() method?
>2) Should there be a join_all(). I'm becoming convinced there
>shouldn't be for various reasons, but with this design in particular
>the semantics will become difficult to detail. The join_all() method
>was first suggested by Jeremy Siek and it certainly makes some things
>simpler to deal with given some other designs, but since we can't
>know which threads are running at the point of call it's a dangerous
>call to make any way.
>3) Should there be comparison operators? With out copy semantics
>you'd always be comparing to yourself, so I'd guess not.
>4) Will the usage of this design make users opt for the native C
>APIs instead of the Boost.Threads library.

If you are worried (and I think it is a reasonable worry until we have
experience to tell us otherwise), then also provide the thread_id (or
thread_desc, thread_handle, or whatever you prefer to call it) procedure
oriented interface.

I know that is asking you to do more work, but neither of these seem
huge. I'll volunteer to do the docs.

If later we decide to deprecate one or the other, it would be on the basis
of hard experience and not just speculation.

> Even if the design is
>superior (I won't claim it is, though that was the goal of everyone
>here) if no one will use it then the design is a failure.
>5) Are the join(), detach() and destructor semantics understandable
>and usable?

They seem OK to me, but what do developers with lots of threading
experience say?

> For example, what happens if you call a method on a
>thread object that's been detached? I would expect an error.

I would expect an error usually too. What are the semantics of
is_alive()? Would is_current() also be an error?

> If
>that's the case should join() detach the thread, or simply wait for
>the thread to finish, being a noop if the thread is already
>finished? wait for finish. detach() right away would be very
counterintuitive to me, (but I only have very light thread experience.)

> Should the destructor detach() the thread or join() it?

Prior examples seemed to show detach() as preferable. You explicitly
join() if you want to wait, otherwise just destroy the object. Although I
don't know if it is a big issue; if ~thread() has join() semantics, you
could always explicitly detach() first. Which would be a more damaging
mistake; to forget to do a join() and have the dtor detach(), or forget to
do a detach() and have the dtor join()?

>6) Should sleep() and yeild() be stand alone methods, and why?
>We'll need good rationale statements for this which ever route we
>go. The rationale for making them static methods is to give them
>access to thread internals, but both current target implementations
>do not have this need, and it's possible (probable?) that no
>implementation will need this.

Flip coin. Comes up static. That way your thread_desc based free
functions can have the same name, if you want (although that may be a bad
idea).

Thanks for keeping going through such protracted discussions!

--Beman


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