The cancel mechanism requests termination of another thread (or itself).
When you request that a thread be canceled, you are requesting that it terminate as soon as possible. However, the target thread can control how quickly it terminates by controlling its cancelability state and type.
A thread's initial cancelability state is enabled. Cancelability state determines whether a thread can receive a cancellation request. If the cancelability state is disabled, the thread does not receive any cancellation requests. The current thread's cancelability state can be changed by calling pthread_setcancelstate.
Initially, a thread's cancelability type is deferred. Deferred cancelability means that threads receive a cancellation request only at cancellation points-for example, when a call to the pthread_cond_wait routine is made. If you set a thread's cancelability type to asynchronous, the thread can receive a cancellation request at any time. The current thread's cancelability type can be changed by calling pthread_setcanceltype.
The following is a list of routines that are cancellation points:
If the cancelability state is enabled, you can request the delivery of any pending cancel request by using the pthread_testcancel or routine. This routine allows you to permit cancellation to occur at places where it might not otherwise be permitted, and it is especially useful within very long loops to ensure that cancel requests are noticed within a reasonable time.
If you set cancelability state to disabled, the thread cannot be terminated by any cancel request. This means that a thread could wait indefinitely if it does not come to a normal conclusion; therefore, exercise care.
When a cancellation request is delivered to a thread, the thread could be holding some resources, such as locked mutexes or allocated memory. Your program must release these resources before the thread terminates. DECthreads provides two equivalent mechanisms that can be used to do the cleanup during cancellation.
You can use the POSIX functions, pthread_cleanup_push and pthread_ cleanup_pop, to establish and remove cleanup handlers for a section of code that contains a cancellation point. When a cancel request is delivered, the routine specified in pthread_cleanup_push is called. This allows the thread to unlock mutexes or otherwise release resources held in the current scope. Each routine can establish one or more cleanup handlers using pthread_cleanup_push. When the handler is no longer needed it is removed by calling pthread_ cleanup_pop. The argument to pthread_cleanup_pop indicates whether the handler routine should be called when it is removed. Calling the cleanup handler automatically on removal is convenient when the thread is about to leave the scope and what you need is to perform the cleanup actions even though the thread wasn't cancelled (for example, releasing the mutex after waking up from a condition variable wait). (See also the pthread reference pages.)
Alternatively, you can use the DECthreads exception package TRY /CATCH or TRY/FINALLY macros to clean up during a cancellation request. A cancellation request is sent to the thread by raising a special DECthreads exception. Thus, code that contains a cancellation point can be placed inside a TRY block, and a CATCH or FINALLY block can be used to release the resources the thread is holding when the cancellation request is sent. Note that code should always reraise the cancellation exception-failing to do so will result in the thread not terminating as requested. (See also Chapter 5.)
Because it is impossible to predict exactly when an asynchronous cancellation request will be delivered, it is extremely difficult to recover properly when an asynchronous cancellation request is delivered. For this reason, an asynchronous cancelability type should only be set within regions of code that do not need to clean up in any way (such as unlocking mutexes or freeing storage). While cancelability type is asynchronous, do not call any routine unless it is explicitly documented as safe to be called with asynchronous cancelability type. Note that none of the general run-time routines and none of the DECthreads routines are safe except for pthread_ setcanceltype.
For additional information on cancellation for your platform, see the appropriate section titled Thread Cancelability of System Services in Section A.4, Section B.9, and Section C.7.
Use the following routines to control the cancelability of threads:
A thread control and cancellation example is shown in Example 2-1.
/* * Pthread Cancel Example */ /* * Outermost cancellation state */ { . . . int s, outer_c_s, inner_c_s; . . . /* Disable cancellation, saving the previous setting. */ s = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &outer_c_s); if(s == EINVAL) printf("Invalid Argument!\n"); else if(s == 0) . . /* Now cancellation is disabled. */ . . . /* Enable cancellation. */ { . . . s = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &inner_c_s); if(s == 0) . . /* Now cancellation is enabled. */ . . . /* Enable asynchronous cancellation this time. */ { . . . /* Enable asynchronous cancellation. */ int outerasync_c_s, innerasync_c_s; . . s = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &outerasync_c_s); if(s == 0) . . /* Now asynchronous cancellation is enabled. */ . . . /* Now restore the previous cancellation state (by * reinstating original asynchronous type cancel). */ s = pthread_setcanceltype (outerasync_c_s, &innerasync_c_s); if(s == 0) . . /* Now asynchronous cancellation is disabled, * but synchronous cancellation is still enabled. */ } . . . } . . . /* Restore to original cancellation state. */ s = pthread_setcancelstate (outer_c_s, &inner_c_s); if(s == 0) . . /* The original (outermost) cancellation state is now reinstated. */ }