C++线程退出清理

一 点睛

POSIX线程库提供了函数pthread_cleanup_push和pthread_cleanup_pop,让线程退出时可以做一些清理工作。这两个函数采用先入后出的栈结构管理,前者会把一个函数压入清理函数栈,后者用来弹出栈顶的清理函数,并根据参数来决定是否执行清理函数。多次调用函数pthread_cleanup_push将把当前栈顶的清理函数往下压,弹出清理函数时,在栈顶清理函数先被弹出。

由pthread_cleanup_push压栈的清理函数在下面3种情况下会执行:

1 线程主动结束,比如return或调用pthread_exit的时候。

2 调用函数pthread_cleanup_pop,且其参数为非0时。

3 线程被其它线程取消时,也就是由其他的线程对该线程调用pthread_cancel函数。

要注意的是,函数pthread_cleanup_push和pthread_cleanup_pop必须成对出现在同一函数中,否则就会出现语法错误。

二 线程主动结束时,调用清理函数

1 代码

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h> //strerror
void mycleanfunc(void *arg)   //清理函数
{
    printf("mycleanfunc:%d\n", *((int *)arg));    //打印传进来的不同参数                     
}
void *thfrunc1(void *arg)
{
    int m=1;
    printf("thfrunc1 comes \n");
    pthread_cleanup_push(mycleanfunc, &m);   //  把清理函数压栈
    return (void *)0;     //退出线程
    pthread_cleanup_pop(0);    //把清理函数出栈,这句不会执行,但必须有,否则编译不过
}
void *thfrunc2(void *arg)
{
    int m = 2;
    printf("thfrunc2 comes \n");
    pthread_cleanup_push(mycleanfunc, &m);        //  把清理函数压栈
    pthread_exit(0);        //退出线程
    pthread_cleanup_pop(0);    //把清理函数出栈,这句不会执行,但必须有,否则编译不过
}


int main(void)
{
    pthread_t pid1,pid2;
    int res;
    res = pthread_create(&pid1, NULL, thfrunc1, NULL);  // 创建线程1
    if (res)
    {
        printf("pthread_create failed: %d\n", strerror(res));
        exit(1);
    }
    pthread_join(pid1, NULL);  //等待线程1结束
    
    res = pthread_create(&pid2, NULL, thfrunc2, NULL);  // 创建线程2
    if (res)
    {
        printf("pthread_create failed: %d\n", strerror(res));
        exit(1);
    }
    pthread_join(pid2, NULL);      //等待线程2结束  
    
    printf("main over\n");
    return 0;
}

2 运行

[root@localhost test]# g++ -o test test.cpp -lpthread
[root@localhost test]# ./test
thfrunc1 comes
mycleanfunc:1
thfrunc2 comes
mycleanfunc:2
main over

3 说明

无论是return还是pthread_exit,都会引起清理函数的执行。值得注意的是,pthread_cleanup_pop必须和pthread_cleanup_push成对出现在同一个函数中,否则编译不过。

三 pthread_cleanup_pop调用清理函数

1 代码

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h> //strerror
void mycleanfunc(void *arg)  //清理函数
{
    printf("mycleanfunc:%d\n", *((int *)arg));                         
}
void *thfrunc1(void *arg)  // 线程函数
{
    int m=1,n=2;
    printf("thfrunc1 comes \n");
    pthread_cleanup_push(mycleanfunc, &m);  //把清理函数压栈
    pthread_cleanup_push(mycleanfunc, &n);  // 再把一个清理函数压栈
    pthread_cleanup_pop(1);  //出栈清理函数,并执行
    pthread_exit(0); //退出线程
    pthread_cleanup_pop(0);  //不会执行,仅为了成对
}
  
int main(void)
{
    pthread_t pid1 ;
    int res;
    res = pthread_create(&pid1, NULL, thfrunc1, NULL);  // 创建线程
    if (res)
    {
        printf("pthread_create failed: %d\n", strerror(res));  
        exit(1);
    }
    pthread_join(pid1, NULL);  //等待线程结束
    
    printf("main over\n");
    return 0;
}

2 运行

[root@localhost test]# g++ -o test test.cpp -lpthread
[root@localhost test]# ./test
thfrunc1 comes
mycleanfunc:2
mycleanfunc:1
main over

3 说明

我们连续压了两次清理函数入栈,第一次压栈的清理函数在栈底,第二次压栈的清理函数就到了栈顶了,出栈的时候应该是第二次压栈的清理函数先执行,因此,输出的整数值应该是2,pthread_exit退出线程时,引发执行的清理函数是传m进去的清理函数,输出的整数值是1.

四 取消线程时引发清理函数

1 代码

#include<stdio.h>  
#include<stdlib.h>  
#include <pthread.h>  
#include <unistd.h> //sleep

void mycleanfunc(void *arg) //清理函数
{
    printf("mycleanfunc:%d\n", *((int *)arg));                         
}
void *thfunc(void *arg)  
{  
    int i = 1;  
    printf("thread start-------- \n");
    pthread_cleanup_push(mycleanfunc, &i); //把清理函数压栈
    while (1)  
    {
        i++;  
        printf("i=%d\n", i);
    }    
    printf("this line will not run\n");
    pthread_cleanup_pop(0);
    
    return (void *)0;  
}  
int main()  
{  
    void *ret = NULL;  
    int iret = 0;  
    pthread_t tid;  
    pthread_create(&tid, NULL, thfunc, NULL);  //创建线程
    sleep(1);  
          
    pthread_cancel(tid); //发送取消线程的请求  
    pthread_join(tid, &ret);  //等待线程结束
    if (ret == PTHREAD_CANCELED) //判断是否成功取消线程
        printf("thread has stopped,and exit code: %d\n", ret);  //打印下返回值,应该是-1
    else
        printf("some error occured");
          
    return 0;  
}

2 运行

[root@localhost test]# g++ -o test test.cpp -lpthread
......
i=285687
i=285688
i=285689
i=285690
i=285691i=285691
mycleanfunc:285691
thread has stopped,and exit code: -1

3 说明

子线程在循环中打印i的值,一直到被取消。由于循环里有系统调用printf,因此取消成功。取消成功的时候,将会执行清理函数,在清理函数中打印的i值将是执行很多次i++后的值,这是因为我们压栈清理函数的时候,传给清理函数的是i的地址,而执行清理函数的时候,i的值已经变了,因此打印的是最新的i值。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值