Boost logo

Boost :

From: Alexander Terekhov (terekhov_at_[hidden])
Date: 2001-06-29 09:58:20


> 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.

> (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!!

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;
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 }

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