Boost logo

Boost :

From: Alexander Terekhov (terekhov_at_[hidden])
Date: 2001-08-16 08:33:16


> > > I note the clever semantics: this call would have to
> > > throw an exception if the thread had been detached.
> > > But there's no call to detach a thread, so it cannot happen:
> > > threads are detached simply by not calling join.
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >
> > really? without ref.counting? i do not understand this.
> > can you explain this?
>
> Unfortunately, to implement this correctly on top of pthreads I think
> we're going to have to ref-count. Not in the same manner as you do
> with a thread_ref concept, but it's still going to need to be done.
> The biggest problem I see to getting this right is in not knowing
> precisely what POSIX defines as the result of calling join() on a
> thread that's already been joined or detached. If it's undefined
> behavior then I'm going to have problems with "adopted" threads.
> We'll have to discuss what the appropriate design/implementation will
> be in that case. Can you enlighten me on this issue?

i do not think that "adopted" threads (main/initial thread
thread aside) would create a real problem.. (pthreads-win32
solves it via some _np functions, which should never been
used in portable programs anyway..)

>If it's undefined behavior then...

yes, behavior is undefined (use of not detached/joinable
thread (id) by _detach/_join more than once is an error;
with an exception of _join been cancelled):

"A conforming implementation is free to reuse a thread
 ID after the thread terminates if it was created with
 the detachstate attribute set to PTHREAD_CREATE_DETACHED
 or if pthread_detach() or pthread_join() has been called
 for that thread. If a thread is detached, its thread ID
 is invalid for use as an argument in a call to
 pthread_detach() or pthread_join()."

"The detachstate attribute controls whether the thread is
 created in a detached state. If the thread is created
 detached, then use of the ID of the newly created thread
 by the pthread_detach() or pthread_join() function is an
 error."

"It has been suggested that a ''detach'' function is not
 necessary; the detachstate thread creation attribute is
 sufficient, since a thread need never be dynamically
 detached. However, need arises in at least two cases:
 1. In a cancelation handler for a pthread_join () it is
 nearly essential to have a pthread_detach() function
 in order to detach the thread on which pthread_join() was
 waiting. Without it, it would be necessary to have
 the handler do another pthread_join () to attempt to
 detach the thread, which would both delay the cancelation
 processing for an unbounded period and introduce a
 new call to pthread_join ( ), which might itself need
 a cancelation handler. A dynamic detach is nearly
 essential in this case.
 2. In order to detach the ''initial thread'' (as may be
 desirable in processes that set up server threads)."

"The pthread_join() function shall suspend execution of
 the calling thread until the target thread terminates,
 unless the target thread has already terminated. On
 return from a successful pthread_join() call with a
 non-NULL value_ptr argument, the value passed to
 pthread_exit() by the terminating thread shall be made
 available in the location referenced by value_ptr.
 When a pthread_join() returns successfully, the target
 thread has been terminated. The results of multiple
 simultaneous calls to pthread_join() specifying
 the same target thread are undefined. If the thread
 calling pthread_join() is canceled, then the target
 thread shall not be detached."

"It is unspecified whether a thread that has exited
 but remains unjoined counts against _PTHREAD_THREADS_MAX."

"The pthread_join() function provides a simple mechanism
 allowing an application to wait for a thread to terminate.
 After the thread terminates, the application may then choose
 to clean up resources that were used by the thread. For
 instance, after pthread_join() returns, any application-
 provided stack storage could be reclaimed. The pthread_join()
 or pthread_detach() function should eventually be called for
 every thread that is created with the detachstate attribute
 set to PTHREAD_CREATE_JOINABLE so that storage associated with
 the thread may be reclaimed."

"The interaction between pthread_join() and cancelation is
 well-defined for the following reasons:
 - The pthread_join() function, like all other
 non-async-cancel-safe functions, can only be called with
 deferred cancelability type.
 - Cancelation cannot occur in the disabled cancelability
 state. Thus, only the default cancelability state need be
 considered. As specified, either the pthread_join() call is
 canceled, or it succeeds, but not both. The difference is
 obvious to the application, since either a cancelation
 handler is run or pthread_join() returns. There are no race
 conditions since pthread_join() was called in the deferred
 cancelability state."

"The pthread_detach() function shall indicate to the
 implementation that storage for the thread thread can be
 reclaimed when that thread terminates. If thread has not
 terminated, pthread_detach( ) shall not cause it to terminate.
 The effect of multiple pthread_detach() calls on
 the same target thread is unspecified."

as for "await_completion" or similar names..

thread termination process begins when

a) thread start routine returns;

b) thread start routine gets interrupted
   with either thread::exit(...) or thread
   cancellation (at some cancellation
   point or inside some async.cancellable
   code fragment).

thread termination process:

1. "stack unwinding"; calling cancellation
   cleanup handlers/C++ destructors;

2. destruction of thread specific data
   (iterative process of calling tsd
    destruction routines);

3. (if detached) auto-destruction of
   "native" thread object.

Q) what do you really want to wait for
   (with respect to not detached/"joinable"
   thread):

I. finish/end of execution with respect
     to thread start routine "normal" flow
     only: **begin of thread termination**;

-or-

II. finish/end of execution with respect
     to thread start routine "normal" flow
     *and* subsequent thread termination
     process: **end of thread termination**;

-or-

III. ultimate end/everything above plus
     destruction of "native" thread
     object (**pthread_join returns**
     and it is safe now to e.g. reclaim
     application provided stack);

<??>

i have suggested to provide an
option/functions which would allow to
wait for both: [I-above] - less than
posix "join" and [III-above] - equal
to posix "join" (default), separately..
i have also suggested that on destruction
of not detached/"joinable" C++ thread
(object), [III-above] should be done
automatically.

regards,
alexander.


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