1PTHREAD_CLEANUP_PUSH(3) Linux Programmer's Manual PTHREAD_CLEANUP_PUSH(3)
2
3
4
6 pthread_cleanup_push, pthread_cleanup_pop - push and pop thread cancel‐
7 lation clean-up handlers
8
10 #include <pthread.h>
11
12 void pthread_cleanup_push(void (*routine)(void *),
13 void *arg);
14 void pthread_cleanup_pop(int execute);
15
16 Compile and link with -pthread.
17
19 These functions manipulate the calling thread's stack of thread-cancel‐
20 lation clean-up handlers. A clean-up handler is a function that is au‐
21 tomatically executed when a thread is canceled (or in various other
22 circumstances described below); it might, for example, unlock a mutex
23 so that it becomes available to other threads in the process.
24
25 The pthread_cleanup_push() function pushes routine onto the top of the
26 stack of clean-up handlers. When routine is later invoked, it will be
27 given arg as its argument.
28
29 The pthread_cleanup_pop() function removes the routine at the top of
30 the stack of clean-up handlers, and optionally executes it if execute
31 is nonzero.
32
33 A cancellation clean-up handler is popped from the stack and executed
34 in the following circumstances:
35
36 1. When a thread is canceled, all of the stacked clean-up handlers are
37 popped and executed in the reverse of the order in which they were
38 pushed onto the stack.
39
40 2. When a thread terminates by calling pthread_exit(3), all clean-up
41 handlers are executed as described in the preceding point. (Clean-
42 up handlers are not called if the thread terminates by performing a
43 return from the thread start function.)
44
45 3. When a thread calls pthread_cleanup_pop() with a nonzero execute ar‐
46 gument, the top-most clean-up handler is popped and executed.
47
48 POSIX.1 permits pthread_cleanup_push() and pthread_cleanup_pop() to be
49 implemented as macros that expand to text containing '{' and '}', re‐
50 spectively. For this reason, the caller must ensure that calls to
51 these functions are paired within the same function, and at the same
52 lexical nesting level. (In other words, a clean-up handler is estab‐
53 lished only during the execution of a specified section of code.)
54
55 Calling longjmp(3) (siglongjmp(3)) produces undefined results if any
56 call has been made to pthread_cleanup_push() or pthread_cleanup_pop()
57 without the matching call of the pair since the jump buffer was filled
58 by setjmp(3) (sigsetjmp(3)). Likewise, calling longjmp(3) (sig‐
59 longjmp(3)) from inside a clean-up handler produces undefined results
60 unless the jump buffer was also filled by setjmp(3) (sigsetjmp(3)) in‐
61 side the handler.
62
64 These functions do not return a value.
65
67 There are no errors.
68
70 For an explanation of the terms used in this section, see at‐
71 tributes(7).
72
73 ┌────────────────────────┬───────────────┬─────────┐
74 │Interface │ Attribute │ Value │
75 ├────────────────────────┼───────────────┼─────────┤
76 │pthread_cleanup_push(), │ Thread safety │ MT-Safe │
77 │pthread_cleanup_pop() │ │ │
78 └────────────────────────┴───────────────┴─────────┘
79
81 POSIX.1-2001, POSIX.1-2008.
82
84 On Linux, the pthread_cleanup_push() and pthread_cleanup_pop() func‐
85 tions are implemented as macros that expand to text containing '{' and
86 '}', respectively. This means that variables declared within the scope
87 of paired calls to these functions will be visible within only that
88 scope.
89
90 POSIX.1 says that the effect of using return, break, continue, or goto
91 to prematurely leave a block bracketed pthread_cleanup_push() and
92 pthread_cleanup_pop() is undefined. Portable applications should avoid
93 doing this.
94
96 The program below provides a simple example of the use of the functions
97 described in this page. The program creates a thread that executes a
98 loop bracketed by pthread_cleanup_push() and pthread_cleanup_pop().
99 This loop increments a global variable, cnt, once each second. Depend‐
100 ing on what command-line arguments are supplied, the main thread sends
101 the other thread a cancellation request, or sets a global variable that
102 causes the other thread to exit its loop and terminate normally (by do‐
103 ing a return).
104
105 In the following shell session, the main thread sends a cancellation
106 request to the other thread:
107
108 $ ./a.out
109 New thread started
110 cnt = 0
111 cnt = 1
112 Canceling thread
113 Called clean-up handler
114 Thread was canceled; cnt = 0
115
116 From the above, we see that the thread was canceled, and that the can‐
117 cellation clean-up handler was called and it reset the value of the
118 global variable cnt to 0.
119
120 In the next run, the main program sets a global variable that causes
121 other thread to terminate normally:
122
123 $ ./a.out x
124 New thread started
125 cnt = 0
126 cnt = 1
127 Thread terminated normally; cnt = 2
128
129 From the above, we see that the clean-up handler was not executed (be‐
130 cause cleanup_pop_arg was 0), and therefore the value of cnt was not
131 reset.
132
133 In the next run, the main program sets a global variable that causes
134 the other thread to terminate normally, and supplies a nonzero value
135 for cleanup_pop_arg:
136
137 $ ./a.out x 1
138 New thread started
139 cnt = 0
140 cnt = 1
141 Called clean-up handler
142 Thread terminated normally; cnt = 0
143
144 In the above, we see that although the thread was not canceled, the
145 clean-up handler was executed, because the argument given to
146 pthread_cleanup_pop() was nonzero.
147
148 Program source
149
150 #include <pthread.h>
151 #include <sys/types.h>
152 #include <stdio.h>
153 #include <stdlib.h>
154 #include <unistd.h>
155 #include <errno.h>
156
157 #define handle_error_en(en, msg) \
158 do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
159
160 static int done = 0;
161 static int cleanup_pop_arg = 0;
162 static int cnt = 0;
163
164 static void
165 cleanup_handler(void *arg)
166 {
167 printf("Called clean-up handler\n");
168 cnt = 0;
169 }
170
171 static void *
172 thread_start(void *arg)
173 {
174 time_t start, curr;
175
176 printf("New thread started\n");
177
178 pthread_cleanup_push(cleanup_handler, NULL);
179
180 curr = start = time(NULL);
181
182 while (!done) {
183 pthread_testcancel(); /* A cancellation point */
184 if (curr < time(NULL)) {
185 curr = time(NULL);
186 printf("cnt = %d\n", cnt); /* A cancellation point */
187 cnt++;
188 }
189 }
190
191 pthread_cleanup_pop(cleanup_pop_arg);
192 return NULL;
193 }
194
195 int
196 main(int argc, char *argv[])
197 {
198 pthread_t thr;
199 int s;
200 void *res;
201
202 s = pthread_create(&thr, NULL, thread_start, NULL);
203 if (s != 0)
204 handle_error_en(s, "pthread_create");
205
206 sleep(2); /* Allow new thread to run a while */
207
208 if (argc > 1) {
209 if (argc > 2)
210 cleanup_pop_arg = atoi(argv[2]);
211 done = 1;
212
213 } else {
214 printf("Canceling thread\n");
215 s = pthread_cancel(thr);
216 if (s != 0)
217 handle_error_en(s, "pthread_cancel");
218 }
219
220 s = pthread_join(thr, &res);
221 if (s != 0)
222 handle_error_en(s, "pthread_join");
223
224 if (res == PTHREAD_CANCELED)
225 printf("Thread was canceled; cnt = %d\n", cnt);
226 else
227 printf("Thread terminated normally; cnt = %d\n", cnt);
228 exit(EXIT_SUCCESS);
229 }
230
232 pthread_cancel(3), pthread_cleanup_push_defer_np(3), pthread_setcancel‐
233 state(3), pthread_testcancel(3), pthreads(7)
234
236 This page is part of release 5.10 of the Linux man-pages project. A
237 description of the project, information about reporting bugs, and the
238 latest version of this page, can be found at
239 https://www.kernel.org/doc/man-pages/.
240
241
242
243Linux 2020-06-09 PTHREAD_CLEANUP_PUSH(3)