27 err_abort (status, "Disable cancel");
28 sleep (1);
29 status = pthread_setcancelstate (
30 state, &state);
31 if (status != 0)
32 err_abort (status, "Restore cancel");
33 } else
34 if ((counter % 1000) == 0)
35 pthread_testcancel ();
36 }
37 }
38
39 int main (int argc, char *argv[])
40 {
41 pthread_t thread_id;
42 void *result;
43 int status;
44
45 status = pthread_create (
46 &thread_id, NULL, thread_routine, NULL);
47 if (status != 0)
48 err_abort (status, "Create thread");
49 sleep (2);
50 status = pthread_cancel (thread_id);
51 if (status != 0)
52 err_abort (status, "Cancel thread");
53
54 status = pthread_join (thread_id, &result);
55 if (status != 0)
56 err_abort (status, "Join thread");
57 if (result == PTHREAD_CANCELED)
58 printf ("Thread canceled at iteration %d\n", counter);
59 else
60 printf ("Thread was not canceled\n");
61 return 0;
62 }
5.3.2 Asynchronous cancelability
Asynchronous cancellation is useful because the "target thread" doesn't need to poll for cancellation requests by using cancellation points. That can be valuable for a thread that runs a tight compute-bound loop (for example, searching for a prime number factor) where the overhead of calling pthread_testcancel might be severe.
Avoid asynchronous cancellation! It is difficult to use correctly and is rarely useful.
The problem is that you're limited in what you can do with asynchronous cancellation enabled. You can't acquire any resources, for example, including locking a mutex. That's because the cleanup code would have no way to determine
whether the mutex had been locked. Asynchronous cancellation can occur at any hardware instruction. On some computers it may even be possible to interrupt some instructions in the middle. That makes it really difficult to determine what the canceled thread was doing.
For example, when you call malloc the system allocates some heap memory for you, stores a pointer to that memory somewhere (possibly in a hardware register), and then returns to your code, which probably moves the return value into some local storage for later use. There are lots of places that malloc might be interrupted by an asynchronous cancel, with varying effects. It might be interrupted before the memory was allocated. Or it might be interrupted after allocating storage but before it stored the address for return. Or it might even return to your code, but get interrupted before the return value could be copied to a local variable. In any of those cases the variable where your code expects to find a pointer to the allocated memory will be uninitialized. You can't tell whether the memory really was allocated yet. You can't free the memory, so that memory (if it was allocated to you) will remain allocated for the life of the program. That's a memory leak, which is not a desirable feature.
Or when you call pthread_mutex_lock
, the system might be interrupted within a function call either before or after locking the mutex. Again, there's no way for your program to find out, because the interrupt may have occurred between any two instructions, even within the pthread_mutex_lock
function, which might leave the mutex unusable. If the mutex is locked, the application will likely end up hanging because it will never be
Call no code with asynchronous cancellation enabled unless you wrote it to be async-cancel safe — and even then, think twice!
You are not allowed to call any function that acquires resources while asynchronous cancellation is enabled. In fact, you should never call pthread_cancel
, pthread_setcancelstate
, and pthread_setcanceltype
. (And there is no reason to call pthread_cancel
with asynchronous cancelability enabled.) No other POSIX orANSI C functions need be async-cancel safe, and you should never call them with asynchronous cancelability enabled.