32.3a — What Is a Cancellation Point?
When a thread has cancellation state ENABLED and type DEFERRED (the default for all new threads), a cancellation request is not acted upon immediately. Instead, it waits until the thread calls one of a specific set of functions known as cancellation points.
Think of a cancellation point as a “safe checkpoint” where the system says: “This is a good moment to check if someone wants me to stop — I’m about to block anyway.”
pthread_cancel()
runs code
sleep()/read()/…
Terminated
Most cancellation point functions are ones that can block the thread for an indefinite time — like waiting for I/O, sleeping, or waiting on a mutex/condition variable. These are natural “pause points” where it’s safe to terminate.
32.3b — SUSv3: Required Cancellation Points
SUSv3 mandates that the following functions must be cancellation points if provided by the implementation. These are the functions where a pending deferred cancellation is guaranteed to fire.
32.3c — Optional & Implementation-Defined Points
A portable program must handle the possibility that calling these may trigger cancellation.
32.3d — Joining a Canceled Thread: PTHREAD_CANCELED
When a thread is canceled via deferred cancellation:
pthread_join(), the retval pointer receives the special constant PTHREAD_CANCELED.void *retval;
pthread_join(tid, &retval);
if (retval == PTHREAD_CANCELED) {
printf("Thread was canceled\n");
} else {
printf("Thread exited normally, value = %ld\n", (long)retval);
}
Code Example 1: TLPI Listing 32-1 — Thread Canceled at sleep()
The classic example from the book. Worker runs infinite loop with sleep(). Main cancels after 3 seconds. Cancellation fires at the sleep() cancellation point.
/* thread_cancel.c — Modeled after TLPI Listing 32-1 */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
static void *
threadFunc(void *arg)
{
int j;
printf("New thread started\n");
for (j = 1; ; j++) {
printf("Loop %d\n", j); /* printf() MAY be a cancellation point */
sleep(1); /* sleep() IS a cancellation point — fires here */
}
/* NOTREACHED */
return NULL;
}
int
main(int argc, char *argv[])
{
pthread_t thr;
int s;
void * res;
s = pthread_create(&thr, NULL, threadFunc, NULL);
if (s != 0) { perror("pthread_create"); exit(EXIT_FAILURE); }
sleep(3); /* Allow thread to run for 3 iterations */
s = pthread_cancel(thr);
if (s != 0) { perror("pthread_cancel"); exit(EXIT_FAILURE); }
s = pthread_join(thr, &res);
if (s != 0) { perror("pthread_join"); exit(EXIT_FAILURE); }
if (res == PTHREAD_CANCELED)
printf("Thread was canceled\n");
else
printf("Thread was not canceled (unexpected)\n");
exit(EXIT_SUCCESS);
}
Code Example 2: Cancellation at read() — I/O Blocking Point
Thread blocks on read() from a pipe. Main thread cancels it while it’s blocked, demonstrating that I/O functions are cancellation points.
/* cancel_on_read.c — Cancellation fires while blocked on read() */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
static int pipefd[2]; /* pipe: [0]=read end, [1]=write end */
static void *
readerThread(void *arg)
{
char buf[64];
ssize_t n;
printf("Reader: waiting for data on pipe (blocking read)...\n");
/* read() is a cancellation point — will fire if cancel pending */
n = read(pipefd[0], buf, sizeof(buf) - 1);
/* If we reach here, we were NOT canceled (data arrived) */
buf[n] = '\0';
printf("Reader: received: %s\n", buf);
return NULL;
}
int
main(void)
{
pthread_t tid;
void *res;
if (pipe(pipefd) != 0) { perror("pipe"); exit(EXIT_FAILURE); }
pthread_create(&tid, NULL, readerThread, NULL);
sleep(2); /* Wait for reader to block on read() */
printf("Main: canceling thread that is blocked on read()\n");
pthread_cancel(tid);
pthread_join(tid, &res);
printf("Main: reader thread %s\n",
res == PTHREAD_CANCELED ? "was canceled (read was a cancel point)"
: "finished normally");
close(pipefd[0]);
close(pipefd[1]);
return 0;
}
Interview Questions — Section 32.3
sleep(), read(), write(), pthread_cond_wait(), sem_wait().printf() is in the stdio group which is in SUSv3’s optional list — an implementation may make it a cancellation point but is not required to. A portable program must handle the possibility. On Linux/glibc it typically is, but don’t rely on it.PTHREAD_CANCELED, which is defined as (void *)-1 on Linux. You compare: if (retval == PTHREAD_CANCELED).openat() to the required list, moved sigpause() from required to optional, and removed usleep() entirely from the standard.pthread_testcancel() inside the loop — covered in Section 32.4.pthread_testcancel() is explicitly listed by SUSv3 as a required cancellation point. Its sole purpose is to act as a cancellation point — if cancellation is pending and enabled when called, the thread terminates there.