Boost logo

Boost :

From: williamkempf_at_[hidden]
Date: 2001-08-19 10:52:00


--- In boost_at_y..., "Alexander Terekhov" <terekhov_at_d...> wrote:
>
> > A noncopyable thread object _is_ a perfect fit
> > for the thread concept if you can guarantee that
> > there is one to one correspondence between the actual
> > threads and the C++ thread objects.
>
> agree.

I only partially agree. I agree with the explicit statement above,
but I don't agree with what the hidden converse meaning is supposed
to imply. Even if there can be a "many to one correspondence between
the actual resource and the C++ objects" a noncopyable design is
still quite valid. Again, the classic example of std::fstream
illustrates this. You can easily open the same file with multiple
C++ object instances.
 
> > Such a design is possible:
> >
> > thread & create(F f);
> > thread & current();
> >
> > [where current() called from within 'f' would
> > return a reference to the same thread object as
> > create().]

This is only possible with ref-counting or other lifetime management
for the objects referenced by the returns above. We've been down
that road.

> i think that the following is also possible:
>
> thread mythread( f );
>
> [where current() called from within 'f' would
> return a reference to mythread thread object]

Only if you gaurantee that "mythread" "joins" before destruction.
Otherwise there may not be a "mythread" to reference when current()
is called. I don't think we can safely do this since "join" will
have to be a cancellation point if/when we add cancellation.

However, the new design would allow a "thread& current()" interface
using TLS to hold the actual thread object... I just don't think it
buys you any thing and would use up a (probably scarce) TLS slot.

> e.g. 'local' threads (pseudo-code):
>
> t f1( .... );
> t f2( .... );
> t f3( .... );
> const t& select( const t&,const t&,const t& );
>
> // single-threaded
> t fst( .... )
> { return select( f1(....),f2(....),f3(....) ); }
>
> // multi-threaded
> t fmt( .... )
> { return select( thread( f1,....),thread( f2,....),thread(
f3,....) ); }
>
> here select function could be invoked as soon as all
> threads would report their return values... with the
> rest/most of threads termination done concurrently with
> respect to select execution... (final "join" cleanup/
> synch done on local thread objects destruction)

Where did select come from? Seems we're going down some different
road in the discussion here, and a road not really pertinent to the
current design.
 
> > Unfortunately, without garbage collection, the references would
become
> > invalid when 'f' returns (without warning.)
>
> why? for "joinable" threads when f returns, nothing terrible
> (with respect to thread objects - C++ and/or native) really
> happens.. only "join" would explicitly destroy native thread
> object (after awaiting thread termination, implicit destruction
> via "detach" aside; IMHO that should only be done for dynamic
> C++ thread objects; btw native thread objects (represented by
> pthread_t/HANDLE) are always dynamic).

You're playing loose with the term "thread object". Does it mean the
thread of execution (and any programmatic state that entails) or the
C++ thread class instance. The former is quite distinct from the
latter. If you mean the former then you've not addressed the concern
at all since the problem is with the C++ object. If you meant the
latter then I don't understand what you mean by "dynamic". The only
meaning that could make what you said valid is for "dynamic" to mean
that the C++ object was created via "new", and there are a LOT of
reasons why that would result in a very poor design.

Bill Kempf


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