Content-type: text/html; charset=UTF-8
#include <pthread.h> void pthread_cleanup_push(void (*routine)(void *), void *arg); void pthread_cleanup_pop(int execute); Compile and link with -pthread.
The pthread_cleanup_push() function pushes routine onto the top of the stack of clean-up handlers. When routine is later invoked, it will be given arg as its argument.
The pthread_cleanup_pop() function removes the routine at the top of the stack of clean-up handlers, and optionally executes it if execute is nonzero.
A cancellation clean-up handler is popped from the stack and executed in the following circumstances:
POSIX.1 permits pthread_cleanup_push() and pthread_cleanup_pop() to be implemented as macros that expand to text containing '{' and '}', respectively. For this reason, the caller must ensure that calls to these functions are paired within the same function, and at the same lexical nesting level. (In other words, a clean-up handler is established only during the execution of a specified section of code.)
Calling longjmp(3) (siglongjmp(3)) produces undefined results if any call has been made to pthread_cleanup_push() or pthread_cleanup_pop() without the matching call of the pair since the jump buffer was filled by setjmp(3) (sigsetjmp(3)). Likewise, calling longjmp(3) (siglongjmp(3)) from inside a clean-up handler produces undefined results unless the jump buffer was also filled by setjmp(3) (sigsetjmp(3)) inside the handler.
Interface | Attribute | Value |
pthread_cleanup_push(), pthread_cleanup_pop() | Thread safety | MT-Safe |
POSIX.1 says that the effect of using return, break, continue, or goto to prematurely leave a block bracketed pthread_cleanup_push() and pthread_cleanup_pop() is undefined. Portable applications should avoid doing this.
In the following shell session, the main thread sends a cancellation request to the other thread:
$ ./a.out New thread started cnt = 0 cnt = 1 Canceling thread Called clean-up handler Thread was canceled; cnt = 0
From the above, we see that the thread was canceled, and that the cancellation clean-up handler was called and it reset the value of the global variable cnt to 0.
In the next run, the main program sets a global variable that causes other thread to terminate normally:
$ ./a.out x New thread started cnt = 0 cnt = 1 Thread terminated normally; cnt = 2
From the above, we see that the clean-up handler was not executed (because cleanup_pop_arg was 0), and therefore the value of cnt was not reset.
In the next run, the main program sets a global variable that causes the other thread to terminate normally, and supplies a nonzero value for cleanup_pop_arg:
$ ./a.out x 1 New thread started cnt = 0 cnt = 1 Called clean-up handler Thread terminated normally; cnt = 0
In the above, we see that although the thread was not canceled, the clean-up handler was executed, because the argument given to pthread_cleanup_pop() was nonzero.
#include <pthread.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #define handle_error_en(en, msg) \ do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0) static int done = 0; static int cleanup_pop_arg = 0; static int cnt = 0; static void cleanup_handler(void *arg) { printf("Called clean-up handler\n"); cnt = 0; } static void * thread_start(void *arg) { time_t start, curr; printf("New thread started\n"); pthread_cleanup_push(cleanup_handler, NULL); curr = start = time(NULL); while (!done) { pthread_testcancel(); /* A cancellation point */ if (curr < time(NULL)) { curr = time(NULL); printf("cnt = %d\n", cnt); /* A cancellation point */ cnt++; } } pthread_cleanup_pop(cleanup_pop_arg); return NULL; } int main(int argc, char *argv[]) { pthread_t thr; int s; void *res; s = pthread_create(&thr, NULL, thread_start, NULL); if (s != 0) handle_error_en(s, "pthread_create"); sleep(2); /* Allow new thread to run a while */ if (argc > 1) { if (argc > 2) cleanup_pop_arg = atoi(argv[2]); done = 1; } else { printf("Canceling thread\n"); s = pthread_cancel(thr); if (s != 0) handle_error_en(s, "pthread_cancel"); } s = pthread_join(thr, &res); if (s != 0) handle_error_en(s, "pthread_join"); if (res == PTHREAD_CANCELED) printf("Thread was canceled; cnt = %d\n", cnt); else printf("Thread terminated normally; cnt = %d\n", cnt); exit(EXIT_SUCCESS); }