PTHREAD_CLEANUP_PUSH - Linux手册页
Linux程序员手册 第3部分
更新日期: 2020-06-09
名称
pthread_cleanup_push,pthread_cleanup_pop-推入和弹出线程取消清理处理程序
语法
#include <pthread.h> void pthread_cleanup_push(void (*routine)(void *), void *arg); void pthread_cleanup_pop(int execute); Compile and link with -pthread.
说明
这些函数操纵调用线程的线程取消清除处理程序的堆栈。清除处理程序是在取消线程时(或在以下所述的各种其他情况下)自动执行的功能;例如,它可能会解锁互斥锁,以便该互斥锁可用于进程中的其他线程。
pthread_cleanup_push()函数将例程推入清理处理程序堆栈的顶部。当例程在以后被调用时,它将被赋予arg作为其参数。
pthread_cleanup_pop()函数会删除清理处理程序堆栈顶部的例程,如果execute非零,则可以选择执行该例程。
在以下情况下,取消清除处理程序将从堆栈中弹出并执行:
- 1.
- 取消线程后,将弹出所有堆叠的清理处理程序并以与将它们推入堆栈的顺序相反的顺序执行。
- 2.
- 当线程通过调用pthread_exit(3)终止时,所有清理处理程序均按照上一点所述的方式执行。 (如果线程通过从线程启动函数执行返回而终止,则不会调用清理处理程序。)
- 3.
- 当线程使用非零执行参数调用pthread_cleanup_pop()时,将弹出并执行最顶层的清除处理程序。
POSIX.1允许将pthread_cleanup_push()和pthread_cleanup_pop()实现为宏,这些宏分别扩展为包含aq {aq和aq} aq的文本。因此,调用者必须确保对这些函数的调用在同一函数内且在相同的词汇嵌套级别上配对。 (换句话说,仅在执行指定的代码段期间才建立清理处理程序。)
如果自跳转缓冲区由setjmp(3)(sigsetjmp(3)填充以来,如果对pthread_cleanup_push()或pthread_cleanup_pop()进行了任何调用而没有该对的匹配调用,则调用longjmp(3)(siglongjmp(3))会产生不确定的结果))。同样,从清理处理程序内部调用longjmp(3)(siglongjmp(3))会产生不确定的结果,除非跳转缓冲区也由处理程序内部的setjmp(3)(sigsetjmp(3))填充。
返回值
这些函数不返回值。
错误说明
没有错误。
属性
有关本节中使用的术语的说明,请参见attribute(7)。
Interface | Attribute | Value |
pthread_cleanup_push(),pthread_cleanup_pop() | Thread safety | MT-Safe |
遵循规范
POSIX.1-2001,POSIX.1-2008。
备注
在Linux上,pthread_cleanup_push()和pthread_cleanup_pop()函数被实现为宏,这些宏分别扩展为包含aq {aq和aq} aq的文本。这意味着在对这些函数的成对调用范围内声明的变量仅在该范围内可见。
POSIX.1说,使用return,break,continue或goto来过早离开一个放在方括号pthread_cleanup_push()和pthread_cleanup_pop()内的块的效果是不确定的。便携式应用程序应避免这样做。
示例
以下程序提供了使用此页面中描述的功能的简单示例。该程序创建一个线程,该线程执行由pthread_cleanup_push()和pthread_cleanup_pop()括起来的循环。此循环每秒增加一次全局变量cnt。根据提供的命令行参数,主线程向另一个线程发送取消请求,或设置一个全局变量,该全局变量导致另一个线程退出其循环并正常终止(通过执行返回)。
在以下Shell会话中,主线程向另一个线程发送取消请求:
$ ./a.out New thread started cnt = 0 cnt = 1 Canceling thread Called clean-up handler Thread was canceled; cnt = 0
从上面可以看到,该线程已被取消,并且取消取消处理程序已被调用,并将全局变量cnt的值重置为0。
在下一次运行中,主程序设置一个全局变量,该变量导致其他线程正常终止:
$ ./a.out x New thread started cnt = 0 cnt = 1 Thread terminated normally; cnt = 2
从上面可以看到,清理处理程序未执行(因为cleanup_pop_arg为0),因此cnt的值未重置。
在下一次运行中,主程序设置一个全局变量,该变量导致另一个线程正常终止,并为cleanup_pop_arg提供一个非零值:
$ ./a.out x 1 New thread started cnt = 0 cnt = 1 Called clean-up handler Thread terminated normally; cnt = 0
在上面的代码中,我们看到尽管未取消线程,但清理处理程序仍被执行,因为赋予pthread_cleanup_pop()的参数非零。
Program source
#include <pthread.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #define handle_error_en(en, msg) \ do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0) static int done = 0; static int cleanup_pop_arg = 0; static int cnt = 0; static void cleanup_handler(void *arg) { printf("Called clean-up handler\n"); cnt = 0; } static void * thread_start(void *arg) { time_t start, curr; printf("New thread started\n"); pthread_cleanup_push(cleanup_handler, NULL); curr = start = time(NULL); while (!done) { pthread_testcancel(); /* A cancellation point */ if (curr < time(NULL)) { curr = time(NULL); printf("cnt = %d\n", cnt); /* A cancellation point */ cnt++; } } pthread_cleanup_pop(cleanup_pop_arg); return NULL; } int main(int argc, char *argv[]) { pthread_t thr; int s; void *res; s = pthread_create(&thr, NULL, thread_start, NULL); if (s != 0) handle_error_en(s, "pthread_create"); sleep(2); /* Allow new thread to run a while */ if (argc > 1) { if (argc > 2) cleanup_pop_arg = atoi(argv[2]); done = 1; } else { printf("Canceling thread\n"); s = pthread_cancel(thr); if (s != 0) handle_error_en(s, "pthread_cancel"); } s = pthread_join(thr, &res); if (s != 0) handle_error_en(s, "pthread_join"); if (res == PTHREAD_CANCELED) printf("Thread was canceled; cnt = %d\n", cnt); else printf("Thread terminated normally; cnt = %d\n", cnt); exit(EXIT_SUCCESS); }
另外参见
pthread_cancel(3),pthread_cleanup_push_defer_np(3),pthread_setcancelstate(3),pthread_testcancel(3),pthreads(7)
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。