1ojrheoo55t64060014359.gif
7 e A/ e$ B) T, u' z7 l
点击上方蓝色字体,关注我们! X) m$ A) U$ w, H7 n
这类似于使用 atexit() 注册进程终止处理函数。
* R) C7 F2 T# j
/ z5 g5 @9 d U7 G线程清理函数用于在线程退出时执行一些资源释放或清理工作,例如关闭文件描述符、释放内存等。5 f& b! H" y9 E* Z1 M1 ] h5 \8 y) |
2 A/ A, i) h; {不同于进程,线程可以注册多个清理函数,这些清理函数以栈的形式管理,栈是一种先进后出的数据结构。 i4 j. x' S; P! g+ y, E: H5 _
7 `: ~& \! J( {4 f6 ~$ I* }2 I0 g. z因此,清理函数的执行顺序与注册顺序相反。1 ?& Q# `5 X* O0 h
$ `6 M1 j! v# u' M5 \" f7 {
在 Linux 中,使用 pthread_cleanup_push() 和 pthread_cleanup_pop() 函数分别向线程的清理函数栈添加和移除清理函数。
+ @; |: ~; }6 |/ `: k. T) d5 d9 g4 R% x
其原型如下:
3 n$ G; K6 g# z. ]0 d8 w$ m) e B0 p8 s
void pthread_cleanup_push(void (*routine)(void *), void *arg);void pthread_cleanup_pop(int execute);2 W" a E6 U/ l3 S5 ]
参数说明:
/ F( b8 |% H0 m4 J$ Rpthread_cleanup_push():用于将清理函数推入栈中。
6 g% d$ W& p3 s9 |7 V4 l! o Kroutine: 指向清理函数的函数指针,清理函数没有返回值,并接受一个 void * 类型的参数。arg: 传递给清理函数的参数,当清理函数执行时,该参数作为 routine() 的输入。
! y" Q4 Z3 p, j/ |. {pthread_cleanup_pop():用于从清理函数栈中弹出最近添加的清理函数。
: O6 _' ?7 u3 _- Y$ R [6 i; h' f- ]execute: 指定是否执行清理函数。如果为 0,则只移除清理函数而不执行它;如果为非 0,则不仅移除还会执行清理函数。9 s4 Q4 o0 n6 w0 I: n P
7 ]+ `8 Y' S. F- _5 d; l' U' S. M
线程清理函数执行的场景:) ~5 q1 `: ]3 @4 K& q# d
当线程调用 pthread_exit()退出时,清理函数会自动执行。当线程响应取消请求时(如通过 pthread_cancel()取消线程),清理函数会被执行。当通过非 0 参数调用 pthread_cleanup_pop() 时,栈顶的清理函数会被执行。! b' A+ j0 T6 S0 b6 m$ a
+ \" ^" `; h, w4 [以下代码展示了如何使用 pthread_cleanup_push() 和 pthread_cleanup_pop() 注册和移除清理函数:
( w2 B! j F3 P( N8 s$ Q
& c5 n: y1 L4 C6 R* jvoid cleanup(void *arg) { printf("Cleaning up: %s3 b' {. n8 q- s% C$ Z
", (char *)arg);}
w3 T4 T x; X1 j3 Yvoid *thread_function(void *arg) { pthread_cleanup_push(cleanup, "Resource 1"); pthread_cleanup_push(cleanup, "Resource 2");
: e: O$ c' I6 l! C2 c# X, M7 m // 模拟线程工作 printf("Thread is running...
7 i) `1 y( P: c0 j% {! [");
4 }) g" v* K# V // 调用pthread_exit()会触发清理函数的执行 pthread_exit(NULL);" s' S( [, h$ @) _" X P% @6 ]
// 清理函数必须成对使用,因此即使退出后也要调用pthread_cleanup_pop pthread_cleanup_pop(1); pthread_cleanup_pop(1);}% X$ i, e8 M1 H& _- g: H
int main() { pthread_t thread;$ D# D$ V+ U7 M& w
// 创建一个线程 if (pthread_create(&thread, NULL, thread_function, NULL) != 0) { perror("Failed to create thread"); return 1; }
. M, c* O6 g; G" v8 e // 等待线程结束 pthread_join(thread, NULL); return 0;}
6 e: Z. T1 S; g) L5 c! L# ?解释说明:
4 x& J# k& g4 a线程中注册了两个清理函数,分别为 "Resource 1" 和 "Resource 2"。当线程调用 pthread_exit() 时,栈中的清理函数按后进先出的顺序执行,因此会先打印 "Cleaning up: Resource 2",再打印 "Cleaning up: Resource 1"。) j1 `% l* X( J
h7 r6 C5 D2 j8 ]! G, ?注意事项:* ~+ o6 E/ N% O; j( x
pthread_cleanup_push() 和 pthread_cleanup_pop() 并不是普通函数,而是宏实现的,必须在相同的作用域内成对出现,不能在代码中分开使用。清理函数只会在线程通过 pthread_exit() 或响应取消请求时执行。
9 m% I) L3 ~; ^$ k如果线程通过 return 语句退出,清理函数不会被执行。
: U s+ M- G" J7 T3 x$ D
4 Y9 B! ~- r4 h" {5 Q3 l; w; {通过使用 pthread_cleanup_push() 和 pthread_cleanup_pop(),可以确保在线程终止时执行所需的清理操作,这在资源管理和异常处理中非常有用。
6 W3 _7 p& }* G2 Q. e* F/ } |' E/ k6 [2 N
清理函数的自动执行使得多线程编程中的资源释放更加简洁、安全。$ n# l' q7 R/ R
55hzlbxh5tf64060014459.jpg
$ B) H, Y0 Y5 l' F& j
aib0uvoos3u64060014559.gif
$ V# d4 i# B9 ?" B2 j2 u点击阅读原文,更精彩~ |