$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: williamkempf_at_[hidden]
Date: 2001-06-30 08:33:19
--- In boost_at_y..., "Alexander Terekhov" <terekhov_at_d...> wrote:
> 
> > The difference is that a detached thread does not
> > need to run to completion (in fact they are
> > usually coded with infinite loops) while a joined
> > thread does.
> 
> Bill, for never ending thread it is absolutely
> irrelevant whether a thread was detached or not!
> The difference is that a detached thread does
> not need to be _joined_ in order to reclaim
> resources (e.g. thread id) -- it will be done
> automatically upon thread termination. In other
> words for not detached threads thread ids stays
> valid until join() is called -- even if a thread
> had already terminated (thread function ended
> via return or pthread_exit) its id/thread
> function return value/etc.. will be preserved
> and will stay preserved until join(). For never
> ending threads reclamation of resources never
> occurs hence there is no difference at all with
> respect to detached status.
Not 100% true.  It's undefined behavior to allow a program to 
terminate with a thread that's never been joined or detached.  
Theoretically such usage could lead to system leaks that can't be 
reclaimed (though in practice I'd be surprised to find an 
implementation that behaves that way).
> > (BTW, the pthreads standard correctly points out that join() is a
> > convenience... detached threads can be "waited on" through a
> > condition variable.
> 
> the new standard appears to strengthen the termination
> guaranties with respect to join. the new version says:
> 
> 33690 ... For instance, after pthread_join ( ) returns, any
> 33691 application-provided stack storage could be reclaimed.
> 
> CV solution does not allow that!!
Yes, it does.  With a CV solution the thread is created detached and 
later the CV is waited on.  That or the thread is immediately 
detached after waiting on the CV.  Both result in the same behavior 
as join().  A join() concept is a convenience, and nothing more.
 
> as for thread object design questions and join/detach please
> consider the following POSIX example attached below -- it
> creates a new thread type (with a capability for timed join).
> Hopefully it will help to clarify matters.
> 
> regards,
> alexander.
> 
> ----
> 
> 6086 /*
> 6087  * Construct a thread variety entirely from existing functions
> 6088  *  with which a join can be done, allowing the join to time 
out.
> 6089  */
> 6090 #include <pthread.h>
> 6091 #include <time.h>
> 
> 6092 struct timed_thread {
> 6093   pthread_t t;
> 6094   pthread_mutex_t m;
> 6095   int exiting;
> 6096   pthread_cond_t exit_c;
> 6097   void *(*start_routine)(void *arg);
> 6098   void *arg;
> 6099   void *status;
> 6100 };
> 6101 typedef struct timed_thread *timed_thread_t;
Ahh... notice you're design uses a CV to implement the join.  You've 
just proven that join() is a convenience ;).
 
> 6102 static pthread_key_t timed_thread_key;
> 6103 static pthread_once_t timed_thread_once = PTHREAD_ONCE_INIT;
> 
> 6104 static void timed_thread_init()
> 6105 {
> 6106   pthread_key_create(&timed_thread_key, NULL);
> 6107 }
> 
> 6108 static void *timed_thread_start_routine(void *args)
> 6109 /*
> 6110  * Routine to establish thread-specific data value and run the 
actual
> 6111  * thread start routine which was supplied to 
timed_thread_create().
> 6112  */
> 6113 {
> 6114   timed_thread_t tt = (timed_thread_t) args;
> 6115   pthread_once(&timed_thread_once, timed_thread_init);
> 6116   pthread_setspecific(timed_thread_key, (void *)tt);
> 6117   timed_thread_exit((tt->start_routine)(tt->arg));
> 6118 }
> 
> 6119 int timed_thread_create(timed_thread_t ttp, const 
pthread_attr_t
> *attr,
> 6120   void *(*start_routine)(void *), void *arg)
> 6121 /*
> 6122  * Allocate a thread which can be used with timed_thread_join
().
> 6123  */
> 6124 {
> 6125   timed_thread_t tt;
> 6126   int result;
> 6127   tt = (timed_thread_t) malloc(sizeof(struct timed_thread));
> 6128   pthread_mutex_init(&tt->m,NULL);
> 6129   tt->exiting = FALSE;
> 6130   pthread_cond_init(&tt->exit_c,NULL);
> 6131   tt->start_routine = start_routine;
> 6132   tt->arg = arg;
> 6133   tt->status = NULL;
> 6134   if ((result = pthread_create(&tt->t, attr,
> 6135         timed_thread_start_routine, (void *)tt)) != 0) {
> 6136     free(tt);
> 6137     return result;
> 6138   }
> 6139   pthread_detach(tt->t);
> 6140   ttp = tt;
> 6141   return 0;
> 6142 }
> 
> 6143 int timed_thread_join(timed_thread_t tt,
> 6144                       struct timespec *timeout,
> 6145                       void **status)
> 6146 {
> 6147   int result;
> 6148   pthread_mutex_lock(&tt->m);
> 6149   result = 0;
> 6150   /*
> 6151    * Wait until the thread announces that it is exiting,
> 6152    * or until timeout.
> 6153    */
> 6154   while (result == 0 && ! tt->exiting) {
> 6155     result = pthread_cond_timedwait(&tt->exit_c, &tt->m, 
timeout);
> 6156   }
> 6157   pthread_mutex_unlock(&tt->m);
> 6158   if (result == 0 && tt->exiting) {
> 6159     *status = tt->status;
> 6160     free((void *)tt);
> 6161     return result;
> 6162   }
> 6163   return result;
> 6164 }
> 
> 6165 void timed_thread_exit(void *status)
> 6166 {
> 6167   timed_thread_t tt;
> 6168   void *specific;
> 6169   if ((specific=pthread_getspecific(timed_thread_key)) == NULL)
{
> 6170     /*
> 6171      * Handle cases which won't happen with correct usage.
> 6172      */
> 6173     pthread_exit( NULL);
> 6174   }
> 6175   tt = (timed_thread_t) specific;
> 6176   pthread_mutex_lock(&tt->m);
> 6177   /*
> 6178    * Tell a joiner that we're exiting.
> 6179    */
> 6180   tt->status = status;
> 6181   tt->exiting = TRUE;
> 6182   pthread_cond_signal(&tt->exit_c);
> 6183   pthread_mutex_unlock(&tt->m);
> 6184  /*
> 6185   * Call pthread exit() to call destructors and really
> 6186   * exit the thread.
> 6187   */
> 6188   pthread_exit(NULL);
> 6189 }
Other than proving my point, I don't see what else this example is 
supposed to prove.
Bill Kempf