一、概念
1、线程可以安排它退出时的清理操作,这与进程的可以用atexit函数安排进程退出时需要调用的函数类似。这样的函数称为线程清理处理程序。线程
可以建立多个清理处理程序,处理程序记录在栈中,所以这些处理程序执行的顺序与他们注册的顺序相反
pthread_cleanup_push(void (*rtn)(void*), void *args)//注册处理程序
pthread_cleanup_pop(int excute)//清除处理程序
2、当执行以下操作时调用清理函数,清理函数的参数由args传入
1)、调用pthread_exit
2)、响应取消请求
3)、用非零参数调用pthread_cleanup_pop
3、清理函数的必要性
也许你会认为线程不需什么清理操作,我可以在退出之前把所有该办的事情办了。但是,你不能确保你的线程永远正常的退出,加入它被取消呢。
清理操作的优越性就在于,如果线程被取消了,那么清理函数会自动调用,这一点你是办不到的
4、清理函数要注意
pthread_cleanup_push() 和 pthread_cleanup_pop() 是用宏定义继承的,宏定义中包含{} ,因此他们两要成对出席那
二、手册 PTHREAD_CLEANUP_PUSH(3) Linux Programmer’s Manual PTHREAD_CLEANUP_PUSH(3) NAME
pthread_cleanup_push, pthread_cleanup_pop - push and pop thread cancellation clean-up handlers
//注册或者销毁线程取消是的清理函数 SYNOPSIS
#include
//包含头文件pthread.h void pthread_cleanup_push(void (*routine)(void *),
void *arg);
void pthread_cleanup_pop(int execute);
Compile and link with -pthread.
//编译连接线程库 DESCRIPTION
These functions manipulate the calling thread’s stack of thread-cancellation clean-up handlers. A clean-up handler is a
function that is automatically executed when a thread is canceled (or in various other circumstances described below);
it might, for example, unlock a mutex so that it becomes available to other threads in the process.
//这两个函数处理线程栈中的取消清理函数。一个清理函数会在线程被取消的时候执行,比如 它可能去解锁一个互斥量 //让它可以在其他线程中被使用 The pthread_cleanup_push() function pushes routine onto the top of the stack of clean-up handlers. When routine is
later invoked, it will be given arg as its argument.
// pthread_cleanup_push()函数会将它的第一个参数指向的函数压入栈的顶端,当栈顶的函数被唤醒的时候,arg就是它的参数 The pthread_cleanup_pop() function removes the routine at the top of the stack of clean-up handlers, and optionally exe-
cutes it if execute is non-zero.
// The pthread_cleanup_pop()函数将栈顶的清理函数从栈中清除,如果 The pthread_cleanup_pop()的参数不是0 的话,清理 // 函数在被取出的时候还会执行 A cancellation clean-up handler is popped from the stack and executed in the following circumstances:
//一个取消清理操作会在一下的情况弹出并执行 1. When a thread is canceled, all of the stacked clean-up handlers are popped and executed in the reverse of the order
in which they were pushed onto the stack.
//当线程被取消的时候,所有的被压入栈的清理函数都将弹出并执行,他们执行的顺序与入栈的顺序相反 2. When a thread terminates by calling pthread_exit(3), all clean-up handlers are executed as described in the preceding
point. (Clean-up handlers are not called if the thread terminates by performing a return from the thread start func-
tion.)
//当一个线程用pthread_exit退出,所有的清理函数回像上面描述的一样执行。如果线程用return返回,那么清理函数不会 //执行 3. When a thread calls pthread_cleanup_pop() with a non-zero execute argument, the top-most clean-up handler is popped
and executed.
//如果线程以非零参数调用 pthread_cleanup_pop(),栈顶的清理函数就会弹出执行 POSIX.1 permits pthread_cleanup_push() and pthread_cleanup_pop() to be implemented as macros that expand to text con-
taining '{' and '}', respectively. For this reason, the caller must ensure that calls to these functions are paired within the same
function, and at the same lexical nesting level. (In other words, a clean-up handler is only established during the execution of a
specified section of code.)
//在POSIX中, pthread_cleanup_push() 和 pthread_cleanup_pop() 是用宏定义继承的,宏定义中包含{}。因此要确保这两个函数 //是成对调用的 Calling longjmp(3) (siglongjmp(3)) produces undefined results if any call has been made to pthread_cleanup_push() or
pthread_cleanup_pop() without the matching call of the pair since the jump buffer was filled by setjmp(3)
(sigsetjmp(3)). Likewise, calling longjmp(3) (siglongjmp(3)) from inside a clean-up handler produces undefined results
unless the jump buffer was also filled by setjmp(3) (sigsetjmp(3)) inside the handler.
//在清理函数中调用longjmp或者siglongjmp都会产生未知的结果,除非他们和setjmp或者sigsetjmp成对的出现 RETURN VALUE
These functions do not return a value.
//这两个函数没有返回值 ERRORS
There are no errors.
//没有错误码 CONFORMING TO
POSIX.1-2001.
NOTES
On Linux, the pthread_cleanup_push() and pthread_cleanup_pop() functions are implemented as macros that expand to text
containing '{' and '}', respectively. This means that variables declared within the scope of paired calls to these functions will
only be visible within that scope.
//在Linux中, pthread_cleanup_push() and pthread_cleanup_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返回的线程不会执行清理操作,以非0参数调用pthread_cleanup_pop或者用pthread_exit退出的线程会执行清理操作 /*DATE: 2015-4-1 *AUTHOR: WJ *DESCRIPTION: 线程清理处理程序 * pthread_cleanup_push(void (*rtn)(void*), void *args)//注册处理程序 * pthread_cleanup_pop(int excute)//清除处理程序 * * 这两个函数要成对的出现,否则编译无法通过 * * 当执行以下操作时调用清理函数,清理函数的参数由args传入 * 1、调用pthread_exit * 2、响应取消请求(请你来验证) * 3、用非零参数调用pthread_cleanup_pop */ #include "apue.h" void *fisrt_clean(void *arg){ printf("%s fisrt clean\n", arg); return(void *)0;} void *second_clean(void *arg){ printf("%s second clean\n", arg); return(void *)0;} void *thread_fun1(void *arg){ printf("new thread 1\n"); pthread_cleanup_push(fisrt_clean, "thread1"); pthread_cleanup_push(second_clean, "thread1"); pthread_cleanup_pop(1); pthread_cleanup_pop(0); return(void *)1;} void *thread_fun2(void *arg){ printf("new thread 2\n"); pthread_cleanup_push(fisrt_clean, "thread2"); pthread_cleanup_push(second_clean, "thread2"); pthread_exit((void *)2); pthread_cleanup_pop(0); pthread_cleanup_pop(0);}int main(){ pthread_t tid1, tid2; int err; err =pthread_create(&tid1, NULL, thread_fun1, NULL); if(err != 0) { printf("create new thread 1failed\n"); return; } err =pthread_create(&tid2, NULL, thread_fun2, NULL); if(err != 0) { printf("create new thread 2failed\n"); return; } sleep(2); return 0 ;} 练习:当一个线程被取消,清理操作会执行 /*DATE: 2015-4-1 *AUTHOR: WJ *DESCRIPTION: 线程清理处理程序 * pthread_cleanup_push(void (*rtn)(void*), void *args)//注册处理程序 * pthread_cleanup_pop(int excute)//清除处理程序 * * 这两个函数要成对的出现,否则编译无法通过 * * 当执行以下操作时调用清理函数,清理函数的参数由args传入 * 1、调用pthread_exit * 2、响应取消请求 * 3、用非零参数调用pthread_cleanup_pop */ #include "apue.h" void *fisrt_clean(void *arg){ printf("%s fisrt clean\n", arg); return(void *)0;} void *second_clean(void *arg){ printf("%s second clean\n", arg); return(void *)0;} void *thread_fun1(void *arg){ printf("new thread 1 start\n"); //设置清理函数 pthread_cleanup_push(fisrt_clean, "thread1"); pthread_cleanup_push(second_clean, "thread1"); //休眠2s,程序回到主线程,让主线程执行取消操作 sleep(2); pthread_cleanup_pop(1); pthread_cleanup_pop(0); printf("new thread 1 over\n"); return(void *)1;} void *thread_fun2(void *arg){ printf("new thread 2 start\n"); //设置清理函数 pthread_cleanup_push(fisrt_clean, "thread2"); pthread_cleanup_push(second_clean, "thread2"); //休眠2s,程序回到主线程,让主线程执行取消操作 sleep(2); printf("new thread 2 over\n"); pthread_exit((void *)2); pthread_cleanup_pop(0); pthread_cleanup_pop(0);}int main(){ pthread_t tid1, tid2; int err; printf("main thread start\n"); //创造新线程 err =pthread_create(&tid1, NULL, thread_fun1, NULL); if(err != 0) { printf("create new thread 1failed\n"); return; } err =pthread_create(&tid2, NULL, thread_fun2, NULL); if(err != 0) { printf("create new thread 2failed\n"); return; } //休眠1s,让新线程设置清理函数 sleep(1); //取消新线程 printf("main thread about to cancel new thread\n"); err = pthread_cancel(tid1); if(err) printf("cancel new thread 1 failed\n"); err = pthread_cancel(tid2); if(err) printf("cancel new thread 2 failed\n"); //等待新线程结束 printf("wait for new thread over\n"); pthread_join(tid1, NULL); pthread_join(tid2, NULL); printf("main thread over\n"); return 0 ;}