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. Java中的不同遍历方式

    已知一个Person类: public class Person implements Comparable<Person>{ String name; String id; public ...

  2. 比特币源码分析--C++11和boost库的应用

    比特币源码分析--C++11和boost库的应用     我们先停下探索比特币源码的步伐,来分析一下C++11和boost库在比特币源码中的应用.比特币是一个纯C++编写的项目,用到了C++11和bo ...

  3. Best Cow Fences POJ - 2018 (二分)

    Farmer John's farm consists of a long row of N (1 <= N <= 100,000)fields. Each field contains ...

  4. python 配置导入方式

    许多连接,如 from setting import redis_config pool= redis.ConnectionPool(**redis_config) r=redis.Redis(con ...

  5. SpringMvc请求处理流程与源码探秘

    流程梳理 dispatcherServlet作为前端控制器的主要作用就是接受请求与处理响应. 不过它不是传统意义上的servlet,它在接受到请求后采用转发的方式,将具体工作交给专业人士去做. 参与角 ...

  6. am335x uboot2016.05 (MLO u-boot.img)执行流程(转)

    am335x的cpu上电后,执行流程:ROM->MLO(SPL)->u-boot.img 第一级bootloader:引导加载程序,板子上电后会自动执行这些代码,如启动方式(SDcard. ...

  7. Linux学习笔记8

    其他常用命令 cd+回车=回车~ 进入当前用户主目录 查看指定进程信息 #ps -ef |grep  进程名 #ps  ---查看属于自己的进程 #ps -aux  查看所有用户的执行进程 换成  p ...

  8. 【Excel】SUMIF 或用 筛选器 实现挑选含有某些字段的值,然后把这些值所对应的后面某列上的值相加

    Background: 挑选含有某些字段的值,然后把这些值所对应的后面某列上的值相加.比如挑选下表中,所有带有“MX104”这个字段的值,然后把它的后面total那一列的值相加. Solution: ...

  9. elementUI的table组件实现setCurrentRow的滚动条定位效果

    在github上咨询了,直接给了代码: https://jsfiddle.net/tk37c5cb/14/

  10. 【树形期望DP】BZOJ3566- [SHOI2014]概率充电器

    [题目大意] 充电器由 n-1 条导线连通了 n 个充电元件.这n-1条导线均有一个通电概率p%,而每个充电元件本身有直接被充电的概率q[i]%.问期望有多少个充电元件处于充电状态? [思路] 第一次 ...