函数原型如下:
void pthread_cleanup_push(void (*routine)(void *),void *arg) void pthread_cleanup_pop(int execute);相关解释
在线程取消时需要对线程进行清理,释放资源,比如释放锁之类。
pthread_cleanup_push()函数会将routine这个函数压入栈顶(这个栈是用于存放清理函数),并且arg是作为routine函数的参数。
pthread_cleanup_pop()函数会将清理函数栈顶的函数弹出。
在push和pop之间,如果线程被取消例如pthread_cancel(),或者线程调用pthread_exit()终止时会将函数依次弹出,并按弹出顺序(所以是跟入栈顺序相反)执行函数。
如果pthread_cleanup_pop()函数的参数非0,那么在pop时也会执行该函数。
push和pop一定要成对使用,可以理解成{和}的关系,少了编译会报缺少{}的错。
pthread_exit退出线程如下程序,在子线程func中依次压入clean1和clean2函数,调用pthread_exit(0)终止。
#include#include pthread_t pt; void clean1(void* arg) { printf("This is clean1.n"); } void clean2(void* arg) { printf("This is clean2.n"); } void* func(void* arg) { pthread_cleanup_push(clean1,NULL); pthread_cleanup_push(clean2,NULL); pthread_exit(0); pthread_cleanup_pop(0); pthread_cleanup_pop(0); } int main() { pthread_create(&pt,NULL,func,NULL); pthread_join(pt,NULL); }
输出如下:
~$ ./demo6 This is clean2. This is clean1.pthread_cancel退出线程
修改main和func函数。
void* func(void* arg)
{
pthread_cleanup_push(clean1,NULL);
pthread_cleanup_push(clean2,NULL);
sleep(2);
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
}
int main()
{
pthread_create(&pt,NULL,func,NULL);
pthread_cancel(pt);
pthread_join(pt,NULL);
}
同样得到输出如下:
~$ ./demo6 This is clean2. This is clean1.pop函数的参数非0
线程正常退出,但是其中pop函数的参数非0。
void* func(void* arg)
{
pthread_cleanup_push(clean1,NULL);
pthread_cleanup_push(clean2,NULL);
sleep(2);
pthread_cleanup_pop(1);
pthread_cleanup_pop(0);
}
int main()
{
pthread_create(&pt,NULL,func,NULL);
pthread_join(pt,NULL);
}
第一个pop弹出函数对应的是clean2,因为栈先进后出,所以clean2函数会被执行,clean1不会:
~$ ./demo6 This is clean2.在push-pop之外退出
子线程在clean2函数被pop之后退出。
void* func(void* arg)
{
pthread_cleanup_push(clean1,NULL);
pthread_cleanup_push(clean2,NULL);
pthread_cleanup_pop(0);
pthread_exit(0);
pthread_cleanup_pop(0);
}
那么clean2被弹出,所以不会执行,但是clean会执行:
~$ ./demo6 This is clean1.return退出
在man pthread_cleanup_push中有这样一段描述 (Clean-up handlers are not called if the thread terminates by performing a return from the thread start function.) ,按照描述是说return导致的退出不会出发线程清理函数。
修改func程序。
void* func(void* arg)
{
pthread_cleanup_push(clean1,NULL);
pthread_cleanup_push(clean2,NULL);
return NULL;
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
}
实际输出如下:
~$ ./demo6 This is clean2. This is clean1.
可以发现即使是return导致的终止也会出发清理函数。
break,continue,goto跳出push-pop 在手册中还有一句描述 POSIX.1 says that the effect of using return, break, continue, or goto to prematurely leave a block bracketed pthread_cleanup_push() and pthread_cleanup_pop() is undefined. Portable applications should avoid doing this.,return,break,continue,goto离开块的行为时没被定义,要尽量避免这种情况。
以goto为例:
void* func(void* arg)
{
pthread_cleanup_push(clean1,NULL);
pthread_cleanup_push(clean2,NULL);
goto a;
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
a:
printf("an");
}
使用goto离开,依旧会出发线程清理函数:
~$ ./demo6 This is clean2. This is clean1.



