pthread_cleanup_push函数用法详解
pthread_cleanup_push函数简介
- 头文件包含
#include <pthread.h>
- 函数定义
void pthread_cleanup_push(void (* routine )(void *),
void * arg );
void pthread_cleanup_pop(int execute );
- 编译链接选项
-pthread
pthread_cleanup_push函数常见使用错误
- 链接错误
undefined reference to `pthread_cleanup_push'
解决办法:添加链接选项
-pthread
- 编译错误
warning: implicit declaration of function ‘pthread_cleanup_push’ [-Wimplicit-function-declaration]
解决办法:包含头文件
#include <pthread.h>
pthread_cleanup_push函数详细描述
这些函数操作调用线程的线程取消清理处理程序堆栈。清除处理程序是一个函数,当线程被取消时(或在下面描述的各种其他情况下)会自动执行;例如,它可能解锁互斥体,以便进程中的其他线程可以使用该互斥体。
pthread_cleanup_push ()函数将routine推到清理处理程序堆栈的顶部。当稍后调用routine时,它将被赋予arg作为其参数。
pthread_cleanup_pop ()函数移除清理处理程序堆栈顶部的例程,如果execute不为零,则执行该例程。
取消清理处理程序将从堆栈中弹出,并在以下情况下执行:
- 当一个线程被取消时,所有堆叠的清理处理程序都会弹出并按照它们被推送到堆栈上的顺序执行。
- 当一个线程通过调用pthread_exit (3)而终止时,所有清理处理程序都将执行,如上一点所述。(如果线程通过执行线程启动函数中的return而终止,则调用清除处理程序not。)
- 当线程使用非零execute参数调用pthread_cleanup_pop ()时,将弹出并执行最上面的清理处理程序。
POSIX.1允许将pthread_cleanup_push ()和pthread_cleanup_pop ()实现为宏,这些宏扩展为分别包含(aqp{(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))填充。
pthread_cleanup_push函数返回值
这些函数不返回值。
pthread_cleanup_push函数错误码
没有错误。
pthread_cleanup_push函数其他说明
在Linux上,pthread_cleanup_push ()和pthread_cleanup_pop ()函数are实现为宏,扩展为分别包含(aq{(aq)和(aq}(aq)的文本。这意味着在对这些函数的成对调用范围内声明的变量将仅在该范围内可见。
POSIX.1指出,使用return 、break 、continue 或goto来过早地留下一个括号为pthread_cleanup_push ()和pthread_cleanup_pop ()的块的效果是不确定的。可移植应用程序应该避免这样做。
pthread_cleanup_push函数使用举例
下面的程序提供了本页所述函数使用的简单示例。该程序创建一个执行由pthread_cleanup_push ()和pthread_cleanup_pop ()组成的循环的线程。这个循环每秒递增一次全局变量cnt 。根据提供的命令行参数,主线程向另一个线程发送取消请求,或者设置一个全局变量,使另一个线程退出循环并正常终止(通过执行return )
在下面的shell会话中,主线程向另一个线程发送取消请求:
$ \fB./a.out\fP
New thread started
cnt = 0
cnt = 1
Canceling thread
Called clean-up handler
Thread was canceled; cnt = 0
从上面,我们看到线程被取消,取消清理处理程序被调用,它将全局变量cnt的值重置为0。
在下一次运行中,主程序设置一个全局变量,使其他线程正常终止:
$ \fB./a.out x\fP
New thread started
cnt = 0
cnt = 1
Thread terminated normally; cnt = 2
从上面,我们看到清理处理程序没有执行(因为cleanup_pop_arg是0),因此cnt的值没有重置。
在下一次运行中,主程序设置一个全局变量,使另一个线程正常终止,并为cleanup_pop_arg :提供一个非零值
$ \fB./a.out x 1\fP
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) \e
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\en");
cnt = 0;
}
static void *
thread_start(void *arg)
{
time_t start, curr;
printf("New thread started\en");
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\en", 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\en");
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\en", cnt);
else
printf("Thread terminated normally; cnt = %d\en", cnt);
exit(EXIT_SUCCESS);
}
评论区