Boost logo

Boost :

From: williamkempf_at_[hidden]
Date: 2001-06-27 11:23:06


--- In boost_at_y..., williamkempf_at_h... wrote:
> --- In boost_at_y..., Beman Dawes <bdawes_at_a...> wrote:
> > At 10:03 AM 6/27/2001, williamkempf_at_h... wrote:
>
> > >Another thing I've thought of over night. This design makes it
> > >impossible to have a self() method, but I think this
> functionality is
> > >a necessity.
> >
> > Yes, you said that before, but I still don't understand why you
> don't just
> > pass a thread ref or pointer to the initial thread function as an
> > argument. Why isn't that satisfactory?
>
> class thread_group
> {
> public:
> void push(thread* thrd);
> void wait_all() {
> // pseudo code
> for each managed thread
> {
> if (managed thread == self)
> throw;
> }
> }
> };
>
> Being passed a reference to the thread in the thread's start
routine
> is not enough for this simple example. It's contrived, but it's
> enough to illustrate the problem to good effect, I believe.
>
> Adding an is_current() to thread would take care of this case, but
as
> we add to the operations that can be performed on a thread, such as
> setting its priority, the need for self() becomes greater. I
> honestly don't think we can do with out this operation.

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. 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. 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? For example, what happens if you call a method on a
thread object that's been detached? I would expect 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? Should the destructor detach() the thread or join() it?
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.

Bill Kempf


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