Boost logo

Boost :

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


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