Boost logo

Boost :

From: williamkempf_at_[hidden]
Date: 2001-06-22 09:21:22


--- In boost_at_y..., "Greg Colvin" <gcolvin_at_u...> wrote:
> From: Ross Smith <ross.s_at_i...>
> > Greg Colvin wrote:
> > >
> > > If one has only the non-copyable thread object then one
> > > is tempted to traffic in raw pointers to that object, with
> > > either the usual risks of dangling pointers or else the
> > > requirement to keep the thread object around forever.
> >
> > Why do you see this as a problem specific to threads? It's
exactly the
> > same for iostreams, and for that matter for anything else that's
> > non-copyable. Making objects non-copyable when the concept they
> > represent isn't naturally copyable is generally considered a
_good_
> > thing by most C++ programmers.
>
> I'm not sure how similar threads are to file streams. For
> files the typical use is to open a file, read and/or write,
> then close the file, which fits well with scoped construction
> and destruction.
>
> For threads the typical use is to spawn a thread and forget
> about it, with the expectation that it will do whatever it
> needs to do and go away on its own when it is done. So it
> is harder to bind a thread object to a scope, and thus harder
> to ensure that pointers to the thread obejct remain valid.
>
> > As for being "tempted to traffic in raw pointers", surely this is
> > exactly the sort of problem std::auto_ptr and boost::shared_ptr
were
> > created to solve?
>
> Yes, and that might be one way to solve it. I think the catch
> is that if you have created a thread and retained no references
> to it you may want it just go away when its function exits.
>
> > Similarly, why have a special create() function instead of an
ordinary
> > constructor, when constructors work perfectly well for every other
> > non-copyable entity (iostreams etc.)?
>
> I was just following Beman's interface, but a static create
> function is one way to avoid leaking raw pointers and to
> encapsulate resource management, and also to avoid the catch
> above (warning -- uncompiled example code, more or less for
> Windows as I remember it):
>
> class thread : noncopyable
> {
> friend class thread_ref;
>
> // All constructors private, so create
> // is the only way to create a thread
> thread(void (*threadfunc)(void*), void* param)
> : threadfunc(threadfunc), param(param), self_ptr(this) {
> id = _beginthread(fun,this);
> }
>
> ~thread() { assert(this != &self()); }
>
> // package up function and parameter for thread creation
> int id;
> void (*threadfunc)(void*);
> void* param;
> static void __cdecl fun(void* arg) {
> thread* p = (thread*)arg;
> try {
> threadfunc(p->param);
> } catch(...) {
> }
> p->self_ptr.reset(0);
> }
>
> // the thread object is destroyed when there is no
thread_ref
> // referring to it and its thread function has returned
> shared_ptr<thread> self_ptr;
>
> public:
>
> static shared_ptr<thread> create(void (*threadfunc)(void*),
void* param)
> return new thread(threadfunc,param));
> }
> static thread & self();
> static void join_all();
> static void sleep(const xtime& xt);
> static void yield();
>
> bool is_alive() const;
> void join();
> };
>
> Another way is to have copyable thread_ref objects that
> allocate and reference-count a non-copyable thread object
> behind the scenes, e.g.
>
> class thread_ref {
> shared_ptr<thread> ptr;
> public:
> thread_ref(void (*threadfunc)(void*), void* param)
> : ptr(thread::create(threadfunc,param)) {}
> bool is_alive() const { return ptr->is_alive(); }
> void join() { ptr->join(); }
> }
>
> If you have thread_ref you would want create(), is_alive()
> and join() to be private members of thread, which befriends
> thread_ref, with the use of shared_ptr just an implementation
> detail.

The J/Thread package takes this approach. It's Thread type is a
proper representation of the thread state while the static create()
method returns a ThreadHandle referencing this object. The actual
Thread object remains as long as a ThreadHandle continues to
reference it or the thread itself continues to execute. Deleting the
thread object directly is undefined behavior. This design is also
unusual when compared to existing standard types, but it may be the
proper compromise here.

Bill Kempf


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