By default, cancellation is pthread_testcancel
that is nothing but a deferred cancellation point. It will return immediately if the thread hasn't been asked to terminate, which allows you to turn any of your functions into cancellation points.
Some systems provide a function to
It might seem that the thread system could automatically release the mutex; but most of the time that's no help. Threads lock mutexes because they're modifying shared data. No other thread can know what data has been modified or what the thread was trying to change, which makes it difficult to fix the data. Now the program is broken. When the mutex is left locked, you can usually tell that something's broken because one or more threads will hang waiting for the mutex.
The only way to recover from terminating a thread with a locked mutex is for the application to be able to analyze all shared data and repair it to achieve a consistent and correct state. That is not impossible, and it is worth substantial effort when an application must be fail-safe. However, it is generally not practical for anything but an embedded system where the application designers control every bit of shared state in the process. You would have to rebuild not only your own program or library state, but also the state affected by any library functions that might be called by the thread (for example, the ANSI C library).
To cancel a thread, you need the thread's identifier, the pthread_t
value returned to the creator by pthread_create
or returned to the thread itself by pthread_self
. Cancelling a thread is asynchronous — that is, when the call to pthread_cancel
returns, the thread has not necessarily been canceled, it may have only been notified that a cancel request is pthread_join
after cancelling it.
If the thread had asynchronous cancelability type set, or when the thread next reaches a deferred cancellation point, the cancel request will be
That is, the thread can clean up and terminate without having to worry about being canceled again.
When a function that is a cancellation point detects a pending cancel request, the function does not return to the caller. The active cleanup handlers will be called, ifthere are any, and the thread will terminate. There is no way to 'handle' cancellation and continue execution — the thread must either defer cancellation entirely or terminate. This is analogous to C++ object destructors, rather than C++ exceptions — the object is allowed to clean up after itself, but it is not allowed to avoid destruction.
The following program, called cancel.c, shows how to write a thread that responds 'reasonably quickly' to deferred cancellation, by calling pthread_ testcancel within a loop.
11-19 The thread function thread_routine loops indefinitely, until canceled, testing periodically for a pending cancellation request. It minimizes the overhead of calling pthread_testcancel by doing so only every 1000 iterations (line 17).
27-35 On a Solaris system, set the thread concurrency level to 2, by calling thr_ setconcurrency. Without the call to thr_setconcurrency, this program will hang on Solaris because thread_routine is 'compute bound' and will not block. The main program would never have another chance to run once thread_routine started, and could not call pthread_cancel.
36-54 The main program creates a thread running thread_routine, sleeps for two seconds, and then cancels the thread. It joins with the thread, and checks the return value, which should be PTHREAD_CANCELED to indicate that it was canceled, rather than terminated normally.
¦ cancel.c
1 #include <pthread.h>
2 #include 'errors.h' 3
4 static int counter;
5
6 /*
7 * Loop until canceled. The thread can be canceled only
8 * when it calls pthread_testcancel, which it does each 1000
9 * iterations. 10 */
11 void *thread_routine (void *arg)
12 {
13 DPRINTF (('thread_routine starting
'));
14 for (counter = 0; ; counter++)
15 if ((counter % 1000) == 0) {
16 DPRINTF (('calling testcancel
'));
17 pthread_testcancel ();
18 }
19 }
20
21 int main (int argc, char *argv[])
22 {
23 pthread_t thread_id;
24 void *result;
25 int status;
26
27 #ifdef sun
28 /*
29 * On Solaris 2.5, threads are not timesliced. To ensure
30 * that our two threads can run concurrently, we need to
31 * increase the concurrency level to 2.
32 */
33 DPRINTF (('Setting concurrency level to 2
'));
34 thr_setconcurrency (2);
35 #endif
36 status = pthread_create (
37 &thread_id, NULL, thread_routine, NULL);
38 if (status != 0)
39 err_abort (status, 'Create thread');
40 sleep (2);
41
42 DPRINTF (('calling cancel
'));
43 status = pthread_cancel (thread_id);
44 if (status != 0)
45 err_abort (status, 'Cancel thread');
46
47 DPRINTF (('calling join
'));