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的參數毫無關係。