电子产业一站式赋能平台

PCB联盟网

搜索
查看: 12|回复: 0
收起左侧

嵌入式Linux:注册线程清理处理函数

[复制链接]

769

主题

769

帖子

5724

积分

四级会员

Rank: 4

积分
5724
发表于 2025-1-4 08:00:00 | 显示全部楼层 |阅读模式

1ojrheoo55t64060014359.gif

1ojrheoo55t64060014359.gif

/ L, ~* Q( a% p* ?; e" z点击上方蓝色字体,关注我们" c( m7 s# L5 e6 n4 x9 Y% L
这类似于使用 atexit() 注册进程终止处理函数。/ h& m( m  N+ l" N7 a- D1 i0 S9 N
4 t! U$ m$ q. q% l0 n
线程清理函数用于在线程退出时执行一些资源释放或清理工作,例如关闭文件描述符、释放内存等。
6 i2 j8 |5 @9 E0 A$ \; K7 [& C% ?7 E- D/ P) q
不同于进程,线程可以注册多个清理函数,这些清理函数以栈的形式管理,栈是一种先进后出的数据结构。& G+ q% K8 k% t3 V% f$ h
' u! H8 f  v" e7 t' q
因此,清理函数的执行顺序与注册顺序相反。9 h( `! K9 F8 [5 C) H) C6 j: C+ L  e

4 R- H, V* L- E; b! C5 A9 i: h在 Linux 中,使用 pthread_cleanup_push() 和 pthread_cleanup_pop() 函数分别向线程的清理函数栈添加和移除清理函数。
  B# _# ?; T# L& [/ L! i
0 b! H$ b1 A+ O" z3 j* V7 U* \其原型如下:
& P) P# j8 O9 o& I+ {# ^' b2 g7 ~1 G% P; V% q$ H
  • void pthread_cleanup_push(void (*routine)(void *), void *arg);void pthread_cleanup_pop(int execute);
    4 L# z) [9 a8 S! ]/ q8 r参数说明:
    + f" S* l, g" g6 Y( n
  • pthread_cleanup_push():用于将清理函数推入栈中。
    ! D5 o; M9 i! B+ f
  • routine: 指向清理函数的函数指针,清理函数没有返回值,并接受一个 void * 类型的参数。
  • arg: 传递给清理函数的参数,当清理函数执行时,该参数作为 routine() 的输入。7 C! X9 {6 k7 }- z2 p2 L
  • pthread_cleanup_pop():用于从清理函数栈中弹出最近添加的清理函数。0 x  O) X0 N8 j5 x  ?
  • execute: 指定是否执行清理函数。如果为 0,则只移除清理函数而不执行它;如果为非 0,则不仅移除还会执行清理函数。! N' M# x! T1 P3 @3 T/ e

    0 `* t( Z& L) S5 j线程清理函数执行的场景:
    2 P$ k2 I) r1 l; _; _  n6 C
  • 当线程调用 pthread_exit()退出时,清理函数会自动执行。
  • 当线程响应取消请求时(如通过 pthread_cancel()取消线程),清理函数会被执行。
  • 当通过非 0 参数调用 pthread_cleanup_pop() 时,栈顶的清理函数会被执行。8 x6 [+ \' s" S0 J# ]! c& o, S
    0 B/ N1 n" f4 e9 V/ G
    以下代码展示了如何使用 pthread_cleanup_push() 和 pthread_cleanup_pop() 注册和移除清理函数:6 i, w6 d  E8 w# X: q

    5 X" G; ~9 ^3 F  q$ |6 e
  • void cleanup(void *arg) {    printf("Cleaning up: %s
    ! @) t/ Q1 l! K9 V. N, ?", (char *)arg);}
    . [& R1 E! S( l$ v( @; {void *thread_function(void *arg) {    pthread_cleanup_push(cleanup, "Resource 1");    pthread_cleanup_push(cleanup, "Resource 2");
    ' W. r3 b  {# q* ?* H    // 模拟线程工作    printf("Thread is running...
    6 K% ]5 j1 B: m0 |");& }( U6 L) a9 t! }
        // 调用pthread_exit()会触发清理函数的执行    pthread_exit(NULL);
    ) l" t# H* X' G) M& D! C' N    // 清理函数必须成对使用,因此即使退出后也要调用pthread_cleanup_pop    pthread_cleanup_pop(1);    pthread_cleanup_pop(1);}
    / a0 E$ G+ A8 M( o: F% O0 Qint main() {    pthread_t thread;# T# ~/ j, J6 }) s6 P: I
        // 创建一个线程    if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {        perror("Failed to create thread");        return 1;    }: B8 U; J" P! _2 |% n$ M
        // 等待线程结束    pthread_join(thread, NULL);    return 0;}
    ; c; `" G; S/ X  T, X, V6 R解释说明:
    # z; _1 j5 T& b) i7 p" J9 h
  • 线程中注册了两个清理函数,分别为 "Resource 1" 和 "Resource 2"。
  • 当线程调用 pthread_exit() 时,栈中的清理函数按后进先出的顺序执行,因此会先打印 "Cleaning up: Resource 2",再打印 "Cleaning up: Resource 1"。
    9 B0 W! @" }$ J4 x0 \7 b2 h* c0 u
    $ X/ w2 w0 Z0 k; B2 t
    注意事项:
    / M4 N" l' {- a( `9 Y( C" j4 n
  • pthread_cleanup_push() 和 pthread_cleanup_pop() 并不是普通函数,而是宏实现的,必须在相同的作用域内成对出现,不能在代码中分开使用。
  • 清理函数只会在线程通过 pthread_exit() 或响应取消请求时执行。% q# I3 S  D) q2 J# D
    如果线程通过 return 语句退出,清理函数不会被执行。6 R$ G4 c7 Z' B  H

    ; z) f! z4 ^2 \+ b6 t' N通过使用 pthread_cleanup_push() 和 pthread_cleanup_pop(),可以确保在线程终止时执行所需的清理操作,这在资源管理和异常处理中非常有用。2 X( f0 ]- M6 }7 d+ G/ \; E

    . U+ C% f1 j. x- F清理函数的自动执行使得多线程编程中的资源释放更加简洁、安全。" Q' a, n7 U0 f% m. _9 k( _4 X; l* X

    55hzlbxh5tf64060014459.jpg

    55hzlbxh5tf64060014459.jpg

    * g- Q- H, ^7 s1 [# ~: S. s

    aib0uvoos3u64060014559.gif

    aib0uvoos3u64060014559.gif

    . K+ C4 S+ w+ `$ {2 t. ?' o, b点击阅读原文,更精彩~
  • 回复

    使用道具 举报

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则


    联系客服 关注微信 下载APP 返回顶部 返回列表