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的参数毫无关系。