POSIX 多线程的 cleanup 函数

控制清理函数的函数有两个,一个是 pthread_cleanup_push(), 用来把清理函数压入栈中,另一个是 pthread_cleanup_pop(), 用来把栈中的函数弹出来。

用这两个函数组合,可以达到在线程退出时,清理线程数据的作用, 例如对 mutex 进行解锁等。

下面是这两个函数的函数原型:

#include <pthread.h>

void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute); //Compile and link with -pthread.

我们先写个简单的例子,感性认识一下这两个函数的作用:

#include <stdio.h>
#include <pthread.h> void handlers(void *arg) {
if(NULL != arg) {
printf("%s() : [%s]\n", __func__, (char*)arg);
} else {
printf("%s()\n", __func__);
}
} void *
thread_start(void *arg) {
pthread_cleanup_push(handlers, "one");
pthread_cleanup_push(handlers, "two");
pthread_cleanup_push(handlers, "thr");
printf("This is thread [%u]\n", (unsigned int)pthread_self());
pthread_exit("he~he~");
//do something
pthread_cleanup_pop();
pthread_cleanup_pop();
pthread_cleanup_pop(); return NULL;
} int main() {
pthread_t pt;
pthread_create(&pt, NULL, thread_start, NULL); void *r = NULL;
pthread_join(pt, &r);
if(NULL != r) {
printf("thread return : [%s]\n", (const char*)r);
} return ;
}

编译并运行:

This is thread []
handlers() : [thr]
handlers() : [two]
handlers() : [one]
thread return : [he~he~]

我们在代码里面是按照 one、two、thr 的顺序调用的 pthread_cleanup_push() 函数, 结果在运行后得到的结果中,却看到它们输出的顺序正好倒过来了。 这正是这对函数的性质。

并且这对函数还有一个性质,那就是使用 pthread_cleanup_push() 和 pthread_cleanup_pop() 之间使用 return 的话,会导致之后的 pthread_cleanup_pop() 不起作用。 这是为什么呢?原因是,其实 pthread_cleanup_push() 和 pthread_cleanup_pop() 不是函数, 而是一对宏。

其宏定义在头文件 pthread.h 中可以看到,宏定义如下:

#  define pthread_cleanup_push(routine, arg) \
do { \
__pthread_cleanup_class __clframe (routine, arg) # define pthread_cleanup_pop(execute) \
__clframe.__setdoit (execute); \
} while ()

我们写个更简单的程序,把这两个宏展开后看一看是什么样结果:

代码如下:

#  define pthread_cleanup_push(routine, arg) \
do { \
__pthread_cleanup_class __clframe (routine, arg) # define pthread_cleanup_pop(execute) \
__clframe.__setdoit (execute); \
} while ()

编译:

gcc -g -E -o pthread_cleanup_macro.i pthread_cleanup_macro.c

查看 pthread_cleanup_macro.i 的代码:

void hand(void* arg) {
printf("do nothing");
} void *thread_start(void* arg) {
do { __pthread_unwind_buf_t __cancel_buf; void (*__cancel_routine) (void *) = (hand); void *__cancel_arg = ("a"); int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *) __cancel_buf.__cancel_jmp_buf, ); if (__builtin_expect((__not_first_call), )) { __cancel_routine (__cancel_arg); __pthread_unwind_next (&__cancel_buf); } __pthread_register_cancel (&__cancel_buf); do {;
printf("This is thread [%u]\n", (unsigned int)pthread_self());
do { } while (); } while (); __pthread_unregister_cancel (&__cancel_buf); if () __cancel_routine (__cancel_arg); } while (); return ((void *));
} int main() {
return ;
}

可以看到,thread_start 函数里面的 pthread_cleanup_push() 和 pthread_cleanup_pop() 已经被展开了。我们把 thread_start 函数里面的代码再修饰一下格式,结果如下:

void *thread_start(void* arg) {
do {
__pthread_unwind_buf_t __cancel_buf;
void (*__cancel_routine) (void *) = (hand);
void *__cancel_arg = ("a");
int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *) __cancel_buf.__cancel_jmp_buf, );
if (__builtin_expect((__not_first_call), )) {
__cancel_routine (__cancel_arg);
__pthread_unwind_next (&__cancel_buf);
}
__pthread_register_cancel (&__cancel_buf);
do {
;
printf("This is thread [%u]\n", (unsigned int)pthread_self());
do {
} while ();
} while ();
__pthread_unregister_cancel (&__cancel_buf);
if () __cancel_routine (__cancel_arg);
} while (); return ((void *));
}

可以看到,我们输出线程信息的 printf 语句,被一层层的 do{}while(0) 给包围了。 如果在 pthread_cleanup_push() 和 pthread_cleanup_pop() 之间加一个 return , 那么整个 do{}while(0) 就会被跳出,后面的代码肯定也就不会被执行了。

同步地址:https://www.fengbohello.top/archives/linux-pthread-cleanup

POSIX 线程清理函数的更多相关文章

  1. POSIX 线程取消点的 Linux 实现

    http://blog.csdn.net/stevenliyong/article/details/4364039 原文链接:http://blog.solrex.cn/articles/linux- ...

  2. 三十七、Linux 线程——线程清理和控制函数、进程和线程启动方式比较、线程的状态转换

    37.1 线程清理和控制函数 #include <pthread.h> void pthread_cleanup_push(void (* rtn)(void *), void *arg) ...

  3. Linux的POSIX线程属性

    创建POSIX线程的函数为 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routin ...

  4. posix 线程(一):线程模型、pthread 系列函数 和 简单多线程服务器端程序

    posix 线程(一):线程模型.pthread 系列函数 和 简单多线程服务器端程序 一.线程有3种模型,分别是N:1用户线程模型,1:1核心线程模型和N:M混合线程模型,posix thread属 ...

  5. POSIX多线程——基本线程管理函数介绍

    POSIX基本的几个线程管理函数见下表: ------------------------------------------------------------------------------- ...

  6. POSIX多线程之创建线程pthread_create && 线程清理pthread_cleanup

    多线程之pthread_create创建线程 pthreads定义了一套C程序语言类型.函数.与常量.以pthread.h和一个线程库实现. 数据类型: pthread_t:线程句柄 pthread_ ...

  7. Posix线程编程指南(4) 线程终止

    线程终止方式 一般来说,Posix的线程终止有两种情况:正常终止和非正常终止.线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退出,这是可预见的退出方式:非正常终止是 ...

  8. Posix线程编程指南(2) 线程私有数据

    概念及作用 在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据.在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有.但有时应用程序设计中有必要提供 ...

  9. POSIX 线程详解 一种支持内存共享的简捷工具

    线程是有趣的 了解如何正确运用线程是每一个优秀程序员必备的素质.线程类似于进程.如同进程,线程由内核按时间分片进行管理.在单处理器系统中,内核使用时间分片来模拟线程的并发执行,这种方式和进程的相同.而 ...

随机推荐

  1. (openssl_pkey_get_private 函数不存在)phpstudy开启openssl.dll 时提示httpd.exe 丢失libssl-1_1.dll

    下载libssl-1_1.dll  丢到apache目录下的bin目录下(貌似要32位的)

  2. hdu5745(dp+bitset)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5745 C++ bitset的用法:https://www.cnblogs.com/magisk/p/880 ...

  3. Apache系列:Apache的全局配置

    配置文件组成: 整个配置文件由3段组成: (1)全局配置:对主服务器或虚拟机都有效,且有些功能是服务器自身工作属性: (2)主服务器:主站属性: (3)虚拟主机:虚拟主机及属性定义 注:第二段和第三段 ...

  4. Spring ConfigurationClassPostProcessor Bean解析及自注册过程

    一.Bean的自注册过程 二.自注册过程说明 ConfigurationClassParser解析流程  1.处理@PropertySources注解,配置信息的解析 2.处理@ComponentSc ...

  5. ps无法存储为PNG

    ps无法存储为PNG,通过各种手段看是否能解决: 第一种:合并图层以后再存储: 第二种:更改存储的名称: 第三种:直接重启ps.

  6. 双11线上压测netty内存泄露

    最近线上压测,机器学习模型第一次应用到线上经历双11大促.JSF微服务有报错 LEAK: ByteBuf.release() was not called before it's garbage-co ...

  7. LOJ.6074.[2017山东一轮集训Day6]子序列(DP 矩阵乘法)

    题目链接 参考yww的题解.本来不想写来但是他有一些笔误...而且有些地方不太一样就写篇好了. 不知不觉怎么写了这么多... 另外还是有莫队做法的...(虽然可能卡不过) \(60\)分的\(O(n^ ...

  8. Ubuntu16.04安装使用wineqq

    目前稳定的wineqq版本为qq2012,官方下载地址->这里 此版本有以下优点: 1.传送文件无问题. 2.支持密码键盘输入并记住密码. 3.可以发送QQ表情无问题. 4.QQ设置常用功能,比 ...

  9. python系统编程(六)

    threading注意点 1. 线程执行代码的封装 通过上一小节,能够看出,通过使用threading模块能完成多任务的程序开发,为了让每个线程的封装性更完美,所以使用threading模块时,往往会 ...

  10. c++语言的设计和演化---在线函数

    开始的c++语言中引入inline函数的目的是处理一些实时的情况,而普通的函数调用的开销无法被接受. 起初是在类的声明中定义inline函数,也只支持成员函数,后来才支持非成员函数: