Pthread学习笔记(3)

Pthread学习笔记(3),第1张

Pthread学习笔记(3) Pthread学习笔记(3) 线程清理 pthread_cleanup_push和pthread_cleanup_pop

  函数原型如下:

void pthread_cleanup_push(void (*routine)(void *),void *arg)
void pthread_cleanup_pop(int execute);
相关解释

  在线程取消时需要对线程进行清理,释放资源,比如释放锁之类。
  pthread_cleanup_push()函数会将routine这个函数压入栈顶(这个栈是用于存放清理函数),并且arg是作为routine函数的参数。
  pthread_cleanup_pop()函数会将清理函数栈顶的函数d出。
  在push和pop之间,如果线程被取消例如pthread_cancel(),或者线程调用pthread_exit()终止时会将函数依次d出,并按d出顺序(所以是跟入栈顺序相反)执行函数。
  如果pthread_cleanup_pop()函数的参数非0,那么在pop时也会执行该函数。

使用

  push和pop一定要成对使用,可以理解成{和}的关系,少了编译会报缺少{}的错。

pthread_exit退出线程

  如下程序,在子线程func中依次压入clean1和clean2函数,调用pthread_exit(0)终止。

#include
#include
pthread_t pt;
void clean1(void* arg)
{
    printf("This is clean1.n");
}
void clean2(void* arg)
{
    printf("This is clean2.n");
}
void* func(void* arg)
{
    pthread_cleanup_push(clean1,NULL);
    pthread_cleanup_push(clean2,NULL);
    pthread_exit(0);
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
}
int main()
{
    pthread_create(&pt,NULL,func,NULL);
    pthread_join(pt,NULL);
}

  输出如下:

~$ ./demo6
This is clean2.
This is clean1.
pthread_cancel退出线程

  修改main和func函数。

void* func(void* arg)
{
    pthread_cleanup_push(clean1,NULL);
    pthread_cleanup_push(clean2,NULL);
    sleep(2);
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
}
int main()
{
    pthread_create(&pt,NULL,func,NULL);
    pthread_cancel(pt);
    pthread_join(pt,NULL);
}

  同样得到输出如下:

~$ ./demo6
This is clean2.
This is clean1.
pop函数的参数非0

  线程正常退出,但是其中pop函数的参数非0。

void* func(void* arg)
{
    pthread_cleanup_push(clean1,NULL);
    pthread_cleanup_push(clean2,NULL);
    sleep(2);
    pthread_cleanup_pop(1);
    pthread_cleanup_pop(0);
}
int main()
{
    pthread_create(&pt,NULL,func,NULL);
    pthread_join(pt,NULL);
}

  第一个popd出函数对应的是clean2,因为栈先进后出,所以clean2函数会被执行,clean1不会:

~$ ./demo6
This is clean2.
在push-pop之外退出

  子线程在clean2函数被pop之后退出。

void* func(void* arg)
{
    pthread_cleanup_push(clean1,NULL);
    pthread_cleanup_push(clean2,NULL);
    pthread_cleanup_pop(0);
    pthread_exit(0);
    pthread_cleanup_pop(0);
}

  那么clean2被d出,所以不会执行,但是clean会执行:

~$ ./demo6
This is clean1.
return退出

  在man pthread_cleanup_push中有这样一段描述 (Clean-up handlers are not called if the thread terminates by performing a return from the thread start function.) ,按照描述是说return导致的退出不会出发线程清理函数。
  修改func程序。

void* func(void* arg)
{
    pthread_cleanup_push(clean1,NULL);
    pthread_cleanup_push(clean2,NULL);
    return NULL;
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
}

  实际输出如下:

~$ ./demo6
This is clean2.
This is clean1.

  可以发现即使是return导致的终止也会出发清理函数。

break,continue,goto跳出push-pop

  在手册中还有一句描述 POSIX.1 says that the effect of using return, break, continue, or goto to prematurely leave a block bracketed pthread_cleanup_push() and pthread_cleanup_pop() is undefined. Portable applications should avoid doing this.,return,break,continue,goto离开块的行为时没被定义,要尽量避免这种情况。
  以goto为例:

void* func(void* arg)
{
    pthread_cleanup_push(clean1,NULL);
    pthread_cleanup_push(clean2,NULL);
    goto a;
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    a:
        printf("an");
}

  使用goto离开,依旧会出发线程清理函数:

~$ ./demo6
This is clean2.
This is clean1.

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5691759.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-17
下一篇2022-12-17

发表评论

登录后才能评论

评论列表(0条)

    保存