pthread_cleanup_push:注册线程退出时的处理程序,与进程的atexit函数类似,只是以压栈的方式储存。
pthread_cleanup_pop:调用已经压栈的线程退出处理程序,当参数非零。
注册的线程退出处理函数仅在以下三种情况下才会被调用:
1、调用pthread_exit退出线程时;
2、响应取消请求时;
3、用非零参数调用pthread_cleanup_pop函数。
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
void cleanup(void *arg)
{
printf("cleanup:%s\n",(char *)arg);
}
void* thr_fn1(void *arg)
{
printf("thread 1 start\n");
pthread_cleanup_push(cleanup,"thread 1 first handler");
pthread_cleanup_push(cleanup,"thread 1 second handler");
printf("thread 1 push complete\n");
if(arg)
{
return (void *)1;
}
pthread_cleanup_pop(1);
printf("here %d\n",__LINE__);
pthread_cleanup_pop(2);
return (void *)1;
}
void* thr_fn2(void *arg)
{
printf("thread 2 start\n");
pthread_cleanup_push(cleanup,"thread 2 first handler");
pthread_cleanup_push(cleanup,"thread 2 second handler");
printf("thread 2 push complete\n");
if(arg)
{
pthread_exit((void *)2);
}
printf("thread 2 is %d\n",__LINE__);
pthread_cleanup_pop(0);
printf("thread 2 here is %d\n",__LINE__);
pthread_cleanup_pop(0);
return (void *)2;
}
int main()
{
int err;
pthread_t tid1,tid2;
void *tret;
err = pthread_create(&tid1,NULL,thr_fn1,(void *)1);
if(0 != err)
{
printf("error:%s\n","cann't create thread 1");
}
err = pthread_create(&tid2,NULL,thr_fn2,(void *)2);
if(0 != err)
{
printf("error:%s\n","cann't create thread 2");
}
err = pthread_join(tid1,&tret);
if(0 != err)
{
printf("error:%s\n","cann't join with thread 1");
}
printf("thread 1 exit code %ld\n",(long)tret);
err = pthread_join(tid2,&tret);
if(0 != err)
{
printf("error:%s\n","cann't join with thread 2");
}
printf("thread 2 exit code %ld\n",(long)tret);
exit(0);
}
注意点:
1、pthread_cleanup_push和pthread_cleanup_pop两个函数必须成对出现,压栈两个就必须弹栈两个,否则编译会报错,而且报的很莫名其妙;
2、调用顺序与压栈的时候恰好相反,如果压栈时fun1 --> fun2;调用的顺序就是fun2 --> fun1。
至于pthread_cleanup_pop的参数貌似只有零和非零的区分。因为此时会调用压栈的函数,而函数的参数是当初压栈的时候就已经确定了,与pthread_cleanup_pop的参数毫无关系。