线程清理函数

线程清理函数

标签(空格分隔): Linux环境编程,多线程


POISX提供了一对线程清理函数。

1. 接口

#include<pthread.h>

void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);

传入的routine函数指针对应的函数即使我们的清理函数。

pthread_cleanup_push()和pthread_cleanup_pop()采用栈结构管理压入的清理函数,在调用pthread_cleanup_push()时将routine函数指针压入清理函数栈,多次对pthread_cleanup_push()的调用将在清理函数栈中形成一个函数链,在执行该函数链时按照与压栈相反的顺序弹出。

pthread_cleanup_pop()用于弹出清理函数,execute参数表示执行到pthread_cleanup_pop()时是否在弹出清理函数的同时执行该函数,为0表示不执行,非0为执行;这个参数并不影响异常终止时(或者说线程在pthread_cleanup_push与和pthread_cleanup_pop之间终止时)清理函数的执行。

从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作(包括调用 pthread_exit()和在取消点终止,还包括return)都将执行pthread_cleanup_push()所指定的清理函数。

2. 示例

2.1

#include <pthread.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <sys/types.h>  

void cleanup(void *arg) {  
    printf("cleanup: %s\n", (char *)arg);  
}  

void *threadFunc(void *arg)  
{  
    printf("thread start\n");  
    pthread_cleanup_push(cleanup, (void*)"thread first handler");  
    pthread_cleanup_push(cleanup, (void*)"thread second handler");  
    if(arg) {  
        printf("we get here, before return in if\n");
        return((void *)1);  
    } else {
        printf("we get here, not return in else\n");
    }
    pthread_cleanup_pop(0);  
    pthread_cleanup_pop(0);  
    printf("we get here, after all pop func finished\n");
    return((void *)1);  
}  

int main(void)  
{  
    int err;  
    pthread_t tid;  
    void *tret;  

    err = pthread_create(&tid, NULL, threadFunc, (void *)1);  
    if(err != 0) {  
        printf("can't create thread: %d\n", err);  
    }  

    err = pthread_join(tid, &tret);  
    if(err != 0) {  
        printf("can't join thread: %d\n", err);  
    }  
    printf("thread exit code %ld\n", (long)tret);  

    return 0;
} 

编译执行:

[root@localhost linux]# g++ threadClean.cpp -lpthread && ./a.out
thread start
we get here, before return in if
cleanup: thread second handler
cleanup: thread first handler
thread exit code 1

2.2 将18行return换成pthread_exit

void *threadFunc(void *arg)  
{  
    printf("thread start\n");  
    pthread_cleanup_push(cleanup, (void*)"thread first handler");  
    pthread_cleanup_push(cleanup, (void*)"thread second handler");  
    if(arg) {  
        printf("we get here, before pthread_exit in if\n");
        //return((void *)1);  
        pthread_exit((void *)1);
    } else {
        printf("we get here, not exit in else\n");
    }
    pthread_cleanup_pop(0);  
    pthread_cleanup_pop(0);  
    printf("we get here, after all pop func finished\n");
    return((void *)1);  
}  

结果类似:

[root@localhost linux]# g++ threadClean.cpp -lpthread && ./a.out
thread start
we get here, before pthread_exit in if
cleanup: thread second handler
cleanup: thread first handler
thread exit code 1

2.3

将传给线程的参数改为0,即不要在pthread_cleanup_push()的调用到pthread_cleanup_pop()之间的让程序终止。

int main(void)  
{  
    int err;  
    pthread_t tid;  
    void *tret;  

    err = pthread_create(&tid, NULL, threadFunc, (void *)0);  
    if(err != 0) {  
        printf("can't create thread: %d\n", err);  
    }  

    err = pthread_join(tid, &tret);  
    if(err != 0) {  
        printf("can't join thread: %d\n", err);  
    }  
    printf("thread exit code %ld\n", (long)tret);  

    return 0;
} 

可见没有执行清理函数cleanup:

[root@localhost linux]# g++ threadClean.cpp -lpthread && ./a.out
thread start
we get here, not exit in else
we get here, after all pop func finished
thread exit code 1

2.4 在2.3基础上将第一个pthread_cleanup_pop的实参改为1

void *threadFunc(void *arg)  
{  
    printf("thread start\n");  
    pthread_cleanup_push(cleanup, (void*)"thread first handler");  
    pthread_cleanup_push(cleanup, (void*)"thread second handler");  
    if(arg) {  
        printf("we get here, before pthread_exit in if\n");
        //return((void *)1);  
        pthread_exit((void *)1);
    } else {
        printf("we get here, not exit in else\n");
    }
    pthread_cleanup_pop(1);  
    pthread_cleanup_pop(0);  
    printf("we get here, after all pop func finished\n");
    return((void *)1);  
}  

发现只执行了栈顶的清理函数:

[root@localhost linux]# g++ threadClean.cpp -lpthread && ./a.out
thread start
we get here, not exit in else
cleanup: thread second handler
we get here, after all pop func finished
thread exit code 1

2.5 现在尝试在第一个pthread_cleanup_push之后就让线程结束

void *threadFunc(void *arg)  
{  
    printf("thread start\n");  
    pthread_cleanup_push(cleanup, (void*)"thread first handler");  
    printf("we exit before exec the 2nd pthread_cleanup_push\n");
    pthread_exit((void *)1);
    pthread_cleanup_push(cleanup, (void*)"thread second handler");  
    if(arg) {  
        printf("we get here, before pthread_exit in if\n");
        //return((void *)1);  
        pthread_exit((void *)1);
    } else {
        printf("we get here, not exit in else\n");
    }
    pthread_cleanup_pop(1);  
    pthread_cleanup_pop(0);  
    printf("we get here, after all pop func finished\n");
    return((void *)1);  
}  

结果:

[root@localhost linux]# g++ threadClean.cpp -lpthread && ./a.out
thread start
we exit before exec the 2nd pthread_cleanup_push
cleanup: thread first handler
thread exit code 1

可见只执行了一个push、pop对。

3. 主要应用

常见的应用是在异常情况下释放锁,形如:

pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);
pthread_mutex_lock(&mut);
/* do some work */
pthread_mutex_unlock(&mut);
pthread_cleanup_pop(0);

当线程在”do some work”中终止时,将主动调用pthread_mutex_unlock(mut),以完成解锁动作。
值得注意的是,如果线程处于PTHREAD_CANCEL_ASYNCHRONOUS状态,上述代码段就有可能出错,因为CANCEL事件可能发生在
pthread_cleanup_push()和pthread_mutex_lock()之间,或者在pthread_mutex_unlock()和pthread_cleanup_pop()之间,从而导致清理函数pthread_mutex_unlock对一个并没有加锁的互斥量解锁造成错误。因此,在使用清理函数的时候,都应该暂时设置成PTHREAD_CANCEL_DEFERRED模式。如:

 int oldCancelType;
 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldCancelType);
 pthread_cleanup_push(routine, arg);
 /* do some work */
 pthread_cleanup_pop(execute);
 pthread_setcanceltype(oldCancelType, NULL);

参考博客:
http://blog.csdn.net/caianye/article/details/5912172
http://blog.csdn.net/cslqm/article/details/53239135#
http://blog.chinaunix.net/uid-26772137-id-3369725.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值