栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Pthread学习笔记(3)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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()函数会将清理函数栈顶的函数弹出。
  在push和pop之间,如果线程被取消例如pthread_cancel(),或者线程调用pthread_exit()终止时会将函数依次弹出,并按弹出顺序(所以是跟入栈顺序相反)执行函数。
  如果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);
}

  第一个pop弹出函数对应的是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被弹出,所以不会执行,但是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.
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/691272.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号