1pthread_cleanup_push(3) Library Functions Manual pthread_cleanup_push(3)
2
3
4
6 pthread_cleanup_push, pthread_cleanup_pop - push and pop thread cance‐
7 lation clean-up handlers
8
10 POSIX threads library (libpthread, -lpthread)
11
13 #include <pthread.h>
14
15 void pthread_cleanup_push(void (*routine)(void *), void *arg);
16 void pthread_cleanup_pop(int execute);
17
19 These functions manipulate the calling thread's stack of thread-cance‐
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 cancelation clean-up handler is popped from the stack and executed in
34 the following circumstances:
35
36 • 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 • 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 • 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 On glibc, the pthread_cleanup_push() and pthread_cleanup_pop() func‐
82 tions are implemented as macros that expand to text containing '{' and
83 '}', respectively. This means that variables declared within the scope
84 of paired calls to these functions will be visible within only that
85 scope.
86
87 POSIX.1 says that the effect of using return, break, continue, or goto
88 to prematurely leave a block bracketed pthread_cleanup_push() and
89 pthread_cleanup_pop() is undefined. Portable applications should avoid
90 doing this.
91
93 POSIX.1-2008.
94
96 POSIX.1-2001. glibc 2.0.
97
99 The program below provides a simple example of the use of the functions
100 described in this page. The program creates a thread that executes a
101 loop bracketed by pthread_cleanup_push() and pthread_cleanup_pop().
102 This loop increments a global variable, cnt, once each second. Depend‐
103 ing on what command-line arguments are supplied, the main thread sends
104 the other thread a cancelation request, or sets a global variable that
105 causes the other thread to exit its loop and terminate normally (by do‐
106 ing a return).
107
108 In the following shell session, the main thread sends a cancelation re‐
109 quest to the other thread:
110
111 $ ./a.out
112 New thread started
113 cnt = 0
114 cnt = 1
115 Canceling thread
116 Called clean-up handler
117 Thread was canceled; cnt = 0
118
119 From the above, we see that the thread was canceled, and that the can‐
120 celation clean-up handler was called and it reset the value of the
121 global variable cnt to 0.
122
123 In the next run, the main program sets a global variable that causes
124 other thread to terminate normally:
125
126 $ ./a.out x
127 New thread started
128 cnt = 0
129 cnt = 1
130 Thread terminated normally; cnt = 2
131
132 From the above, we see that the clean-up handler was not executed (be‐
133 cause cleanup_pop_arg was 0), and therefore the value of cnt was not
134 reset.
135
136 In the next run, the main program sets a global variable that causes
137 the other thread to terminate normally, and supplies a nonzero value
138 for cleanup_pop_arg:
139
140 $ ./a.out x 1
141 New thread started
142 cnt = 0
143 cnt = 1
144 Called clean-up handler
145 Thread terminated normally; cnt = 0
146
147 In the above, we see that although the thread was not canceled, the
148 clean-up handler was executed, because the argument given to
149 pthread_cleanup_pop() was nonzero.
150
151 Program source
152
153 #include <errno.h>
154 #include <pthread.h>
155 #include <stdio.h>
156 #include <stdlib.h>
157 #include <sys/types.h>
158 #include <unistd.h>
159
160 #define handle_error_en(en, msg) \
161 do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
162
163 static int done = 0;
164 static int cleanup_pop_arg = 0;
165 static int cnt = 0;
166
167 static void
168 cleanup_handler(void *arg)
169 {
170 printf("Called clean-up handler\n");
171 cnt = 0;
172 }
173
174 static void *
175 thread_start(void *arg)
176 {
177 time_t curr;
178
179 printf("New thread started\n");
180
181 pthread_cleanup_push(cleanup_handler, NULL);
182
183 curr = time(NULL);
184
185 while (!done) {
186 pthread_testcancel(); /* A cancelation point */
187 if (curr < time(NULL)) {
188 curr = time(NULL);
189 printf("cnt = %d\n", cnt); /* A cancelation point */
190 cnt++;
191 }
192 }
193
194 pthread_cleanup_pop(cleanup_pop_arg);
195 return NULL;
196 }
197
198 int
199 main(int argc, char *argv[])
200 {
201 pthread_t thr;
202 int s;
203 void *res;
204
205 s = pthread_create(&thr, NULL, thread_start, NULL);
206 if (s != 0)
207 handle_error_en(s, "pthread_create");
208
209 sleep(2); /* Allow new thread to run a while */
210
211 if (argc > 1) {
212 if (argc > 2)
213 cleanup_pop_arg = atoi(argv[2]);
214 done = 1;
215
216 } else {
217 printf("Canceling thread\n");
218 s = pthread_cancel(thr);
219 if (s != 0)
220 handle_error_en(s, "pthread_cancel");
221 }
222
223 s = pthread_join(thr, &res);
224 if (s != 0)
225 handle_error_en(s, "pthread_join");
226
227 if (res == PTHREAD_CANCELED)
228 printf("Thread was canceled; cnt = %d\n", cnt);
229 else
230 printf("Thread terminated normally; cnt = %d\n", cnt);
231 exit(EXIT_SUCCESS);
232 }
233
235 pthread_cancel(3), pthread_cleanup_push_defer_np(3), pthread_setcancel‐
236 state(3), pthread_testcancel(3), pthreads(7)
237
238
239
240Linux man-pages 6.04 2023-03-30 pthread_cleanup_push(3)