Книга: Programming with POSIX® Threads
2.2.4 Termination
2.2.4 Termination
A thread usually terminates by returning from its start function (the one you pass to the pthread_create
function). The thread shown in lifecycle.c terminates by returning the value NULL, for example. Threads that call pthread_exit
or that are canceled using pthread_cancel
also terminate after calling each cleanup handler that the thread registered by calling pthread_cleanup_push
and that hasn't yet been removed by calling pthread_cleanup_pop. Cleanup handlers are discussed in Section 5.3.3.
Threads may have private "thread-specific data" values (thread-specific data is discussed in Section 5.4). If the thread has any non-NULL thread-specific data values, the associated destructor functions for those keys (if any) are called.
If the thread was already detached it moves immediately to the next section, recycling. Otherwise, the thread becomes terminated. It will remain available for another thread to join with it using pthread_join
. This is analogous to a UNIX process that's terminated but hasn't yet been "reaped" by a wait operation. Sometimes it is called a "zombie" because it still exists even though it is "dead." A zombie may retain most or all of the system resources that it used when running, so it is not a good idea to leave threads in this state for longer than necessary. Whenever you create a thread with which you won't need to join, you should use the detachstate attribute to create it "detached" (see Section 5.2.3).
At a minimum, a terminated thread retains the identification (pthread_t
value) and the void*
return value that was returned from the thread's start function or specified in a call to pthread_exit
. The only external difference between a thread that terminated "normally" by returning or calling pthread_exit
, and one that terminated through cancellation, is that a cancelled thread's return value is always PTHREAD_CANCELLED. (This is why "cancelled" is not considered a distinct thread state.)
If any other thread is waiting to join with the terminating thread, that thread is awakened. It will return from its call to pthread_join
with the appropriate return value. Once pthread_join
has extracted the return value, the terminated thread is detached by pthread_join
, and may be recycled before the call to pthread_join
returns. This means that, among other things, the returned value should never be a stack address associated with the terminated thread's stack— the value at that address could be overwritten by the time the caller could use it. In lifecycle. c, the main thread will return from the pthread_join call
at line 23 with the value NULL.
pthread_join is a convenience, not a rule.
Even when you need a return value from a thread that you create, it is often at least as simple to create the thread detached and devise your own customized return mechanism as it is to use pthread_join
. For example, if you pass information to a worker thread in some form of structure that another thread can find later, you might have the worker thread simply place the result in that same
structure and broadcast a condition variable when done. The Pthreads context for the thread, including the thread identifier, can then be recycled immediately when the thread is done, and you still have the part you really need, the return value, where you can find it easily at any time.
If pthread_join does exactly what you want, then by all means use it. But remember that it is nothing more than a convenience for the simplest and most limited model of communicating a thread's results. If it does not do exactly what you need, build your own return mechanism instead of warping your design to fit the limitations ofpthread_join.