Yangshazhou November 2001
This is a column for POSIX thread programming. The author will tell you the POSIX thread library API on the basis of clarifying the concept. This article is the fourth article will tell you about threads.
1. Thread termination is generally, POSIX's thread termination has two cases: normally termination and abnormal termination. Thread active call pthread_exit () or from the thread function will make the thread normal exit, which is a foreseeable exit method; abnormal termination is the thread under the intervention of other threads, or due to its own operation (such as access illegal address) And exit, this exit method is unpredictable.
2. The cleaning of threads is terminated whether the foreseeable thread termination or abnormal termination will exist in resource release. Do not consider how to release the resources you occupied smoothly when the thread is terminated without considering the end of the thread. , Especially lock resources, is a problem that must be considered.
The most frequent situation is the use of resource exclusive locks: threads add locks to access critical resources, but cancels them in the access process, if the thread is in response to cancel status, and use asynchronous mode response, or open exclusive There is a cancel point on the previously running path before, and the critical resources will always be released. The external cancellation operation is unpredictable, so a mechanism does require a mechanism to simplify programming for resource release.
A PTHREAD_CLEANUP_PUSH () function is provided in the POSIX thread API to automatically release resources - from pthread_cleanup_push () Termination action (including call pthread_exit) And cancel point termination) will execute the cleaning function specified by pthread_cleanup_push (). The API is defined as follows:
Void pthread_cleanup_push (void (* routine) (void *), void * arg)
Void pthread_cleanup_pop (int execute)
PTHREAD_CLEANUP_PUSH () / pthread_cleanup_pop () Adopt the stack structure management of the first insert, the Void Routine (Void * arg) function is pressed into the cleaning function stack when calling pthread_cleanup_push (), and the call to pThread_cleanup_push () will be in the cleaning function stack. Form a function chain that pops up in the opposite order of the stack when performing the function chain. The execute parameter indicates whether the function is executed while popping up the cleaning function while popping up the cleaning function, and is not executed, not 0 is executed; this parameter does not affect the execution of the cleaning function when the exception is terminated.
PThread_cleanup_push () / pthread_cleanup_pop () is implemented with macro mode, which is a macro definition in pthread.h:
#define pthread_cleanup_push (Routine, Arg) /
{struct _pthread_cleanup_buffer _buffer; /
_Pthread_cleanup_push (& _Buffer, (Routine), (arg));
#define pthread_cleanup_pop (Execute) /
_pthread_cleanup_pop (& _Buffer, (Execute));
It can be seen that pthread_cleanup_push () has a "{", and pthread_cleanup_pop () has a "}", so the two functions must appear pair, and must be in the code segment of the program to be compiled. In the following example, when the thread is terminated in the "Do Some Work", PTHREAD_MUTEX_UNLOCK (MUT) is actively called to complete the unlocking action. Pthread_cleanup_push (pthread_mutex_unlock, (void *) & mut);
PTHREAD_MUTEX_LOCK (& MUT);
/ * do some work * /
Pthread_mutex_unlock (& mut);
Pthread_cleanup_pop (0);
It must be noted that if the thread is in the pthread_cancel_asynchronous state, the above code segment may be wrong because the Cancel event occurs between pthread_cleanup_push () and pthread_mutex_lock (), or between pthread_muteanup_pop (), Thus, the cleaning function UNLOCK does not lock the MUTEX variable, resulting in an error. Therefore, when using the cleaning function, it should be temporarily set to pthread_cancel_deferred mode. To this end, POSIX's Linux implementation also provides a pair of pthread_cleanup_push_deact_np () / pthread_deaternup_pop_defer_np () extensions that do not guarantee portable, and the function is equivalent to the following code segment:
{INT OLDTYPE;
Pthread_setcanceltype (pthread_cancel_deferred, & oldtype);
Pthread_cleanup_push (routine, arg);
...
Pthread_cleanup_pop (execute);
Pthread_setcanceltype (OldType, Null);
}
3. The synchronization of thread termination and its return value are in general, the operation of each thread in the process is independent of each other, and the termination of the thread will not notify, nor does it affect other threads, and the resources occupied by the termination are not As the thread is terminated, it is released. As the process can be used in a WAIT () system call to terminate and release the resource, there is a similar mechanism between the threads, that is, the pthread_join () function.
Void pthread_exit (void * retval)
INT PTHREAD_JOIN (PTHREAD_T TH, VOID ** THREAD_RETURN)
INT PTHREAD_DETACH (PTHREAD_T TH)
The caller of pthread_join () will hang and wait for the TH thread to terminate, retby is the return value of the pthread_exit () caller thread (thread ID), if thread_return is not null, then * thread_return = RetVal. It should be noted that a thread only allows a unique thread to use pthread_join () waiting for its termination, and the waiting thread should be in a JOIN state, ie non-DETACHED state.
If a thread in the process executes PTHREAD_DETACH (TH), the TH thread will be in the Detached state, which makes the TH thread release the memory resources occupied by the end of the runtime, and cannot be synchronized by pthread_join (), pthread_detach () After execution, request PTHREAD_JOIN () will return an error. The memory occupied by Join thread is only released after the thread is performed. Therefore, in order to avoid memory leaks, all threads are terminated, either set to Detached, or need to use pthread_join () Recycle.
4. About PTHREAD_EXIT () and RETURN Theory, the function of pthread_exit () and line-encyclopface function exits the same, and the function is automatically invoke pthread_exit () to clean up the thread-related resources at the end of the function. But in fact, both are great due to the processing of the compiler.
In the process main function (Main ()), calling pthread_exit (), only the thread (which can be said to be the main thread of the process); if it is return, the compiler will make the process exiting the process ( Such as _exit ()), causing the process and all its threads to end running.
Second, the RETURN is actively called in the line retrienet, if the return statement is included in the pthread_cleanup_push () pair, the execution of the cleaning function will not cause segment fault.