电子产业一站式赋能平台

PCB联盟网

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

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

[复制链接]

1001

主题

1001

帖子

8807

积分

高级会员

Rank: 5Rank: 5

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

1ojrheoo55t64060014359.gif

1ojrheoo55t64060014359.gif
- s, z7 W+ N. J) }! s, w% o
点击上方蓝色字体,关注我们
3 I* w* c3 H1 H- d) ~* T2 E这类似于使用 atexit() 注册进程终止处理函数。
+ u1 G! [# V- @- I" `
# ?  j2 A( x' a# G1 Y  m7 U3 L$ `线程清理函数用于在线程退出时执行一些资源释放或清理工作,例如关闭文件描述符、释放内存等。
$ Y3 S: ?$ x$ _' \1 k2 Z/ L0 q2 o8 r1 t5 I2 h' l; q( i9 U
不同于进程,线程可以注册多个清理函数,这些清理函数以栈的形式管理,栈是一种先进后出的数据结构。
6 A0 `8 U  s- ~* E
0 x7 o% [1 l' U- v# c- l+ f9 Z因此,清理函数的执行顺序与注册顺序相反。
/ R6 p* c8 ]$ |* }7 T! h: m6 a" E
6 R4 N% S' l: j在 Linux 中,使用 pthread_cleanup_push() 和 pthread_cleanup_pop() 函数分别向线程的清理函数栈添加和移除清理函数。  s* m* u: k% c: n) \+ y

' C+ O- u$ {0 B* H, G0 S) A其原型如下:
/ ~( |3 T- w5 Z* E: K
- O( r; E" p$ s' L6 x2 C- ]
  • void pthread_cleanup_push(void (*routine)(void *), void *arg);void pthread_cleanup_pop(int execute);6 m& k& G! l- o& `3 g
    参数说明:
    . {4 x# Q8 {5 N/ ~; M  e3 J
  • pthread_cleanup_push():用于将清理函数推入栈中。
    & e6 d7 S1 m  z3 u* `
  • routine: 指向清理函数的函数指针,清理函数没有返回值,并接受一个 void * 类型的参数。
  • arg: 传递给清理函数的参数,当清理函数执行时,该参数作为 routine() 的输入。
    ) `. n( V: r3 b* ~/ W) E, x
  • pthread_cleanup_pop():用于从清理函数栈中弹出最近添加的清理函数。
    . N( ^& W$ c* ?# T
  • execute: 指定是否执行清理函数。如果为 0,则只移除清理函数而不执行它;如果为非 0,则不仅移除还会执行清理函数。4 N: k1 C4 g& i0 s" t

    1 a1 b% X: c7 h, ]' T! E* E9 g! F线程清理函数执行的场景:
    2 F/ y6 T# j' r! z% m8 f
  • 当线程调用 pthread_exit()退出时,清理函数会自动执行。
  • 当线程响应取消请求时(如通过 pthread_cancel()取消线程),清理函数会被执行。
  • 当通过非 0 参数调用 pthread_cleanup_pop() 时,栈顶的清理函数会被执行。
      D8 ]) C& V' o, r" `

    " B8 x+ M( ~6 o& H以下代码展示了如何使用 pthread_cleanup_push() 和 pthread_cleanup_pop() 注册和移除清理函数:
    / p0 q# ^' Y$ _. E# T# V
    8 [$ {" T) W9 W: {
  • void cleanup(void *arg) {    printf("Cleaning up: %s
    ' O" m1 m4 V( _& b", (char *)arg);}
    ( R  t5 b7 s. zvoid *thread_function(void *arg) {    pthread_cleanup_push(cleanup, "Resource 1");    pthread_cleanup_push(cleanup, "Resource 2");
    2 y9 v( e! L3 P    // 模拟线程工作    printf("Thread is running...5 h+ Q7 p4 _2 m4 P
    ");+ n2 Y- i+ R  D1 m  m4 I8 ?: u
        // 调用pthread_exit()会触发清理函数的执行    pthread_exit(NULL);
    3 W* k$ R3 X$ N8 L! ~    // 清理函数必须成对使用,因此即使退出后也要调用pthread_cleanup_pop    pthread_cleanup_pop(1);    pthread_cleanup_pop(1);}; u) A, S; n) i" Y6 t* O) J5 M1 k
    int main() {    pthread_t thread;
    2 P& c2 f- r" n5 d" _: I    // 创建一个线程    if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {        perror("Failed to create thread");        return 1;    }
    8 w) {  a7 }/ K+ Y    // 等待线程结束    pthread_join(thread, NULL);    return 0;}; ~. T4 m4 e. d% j5 [$ h: c
    解释说明:
    ; t- Y- U- ]" M% e. S
  • 线程中注册了两个清理函数,分别为 "Resource 1" 和 "Resource 2"。
  • 当线程调用 pthread_exit() 时,栈中的清理函数按后进先出的顺序执行,因此会先打印 "Cleaning up: Resource 2",再打印 "Cleaning up: Resource 1"。
    ' F$ ]: T3 F0 Y* D7 X& x* E0 c
    2 N1 n5 Y) A8 M8 y& y3 F6 ]+ G
    注意事项:
    9 i6 h+ {/ ^5 J0 z
  • pthread_cleanup_push() 和 pthread_cleanup_pop() 并不是普通函数,而是宏实现的,必须在相同的作用域内成对出现,不能在代码中分开使用。
  • 清理函数只会在线程通过 pthread_exit() 或响应取消请求时执行。
    + `( N" |- [. h0 e7 Y7 @如果线程通过 return 语句退出,清理函数不会被执行。
    9 H$ q7 G: g1 ?* O$ v

    ( x) K2 }, H& C$ O5 t& m8 s通过使用 pthread_cleanup_push() 和 pthread_cleanup_pop(),可以确保在线程终止时执行所需的清理操作,这在资源管理和异常处理中非常有用。$ j, |4 P% X: J( u7 j  c
      p& m4 ^1 o  G5 A( S9 P2 j8 _' g0 S
    清理函数的自动执行使得多线程编程中的资源释放更加简洁、安全。, q7 Q: Q- s( f% ]2 C$ k3 c$ B4 _

    55hzlbxh5tf64060014459.jpg

    55hzlbxh5tf64060014459.jpg

    # t9 A- V& s, `- [; W2 ?

    aib0uvoos3u64060014559.gif

    aib0uvoos3u64060014559.gif

    ) y8 r) i$ F/ b点击阅读原文,更精彩~
  • 回复

    使用道具 举报

    发表回复

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

    本版积分规则


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