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(1);pthread_cleanup_pop(1);pthread_cleanup_pop(1);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 0;
}

编译并运行:

This is thread [3290769152]
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 (0)

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

代码如下:

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

编译:

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, 0); if (__builtin_expect((__not_first_call), 0)) { __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 (0); } while (0); __pthread_unregister_cancel (&__cancel_buf); if (1) __cancel_routine (__cancel_arg); } while (0);return ((void *)0);
}int main() {return 0;
}

可以看到,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, 0); if (__builtin_expect((__not_first_call), 0)) { __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 (0); } while (0); __pthread_unregister_cancel (&__cancel_buf); if (1) __cancel_routine (__cancel_arg); } while (0);return ((void *)0);
}

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

本文转自郝峰波博客园博客,原文链接:http://www.cnblogs.com/fengbohello/p/7571730.html,如需转载请自行联系原作者

POSIX 线程清理函数相关推荐

  1. APUE2勘误-11.5节 线程终止(关于线程清理处理程序)

    平台:Linux 2.6.28-19-generic 书中讲解所用的linux版本为Linux 2.4.22,我没有在此版本上做实验的机会,只是在当前用的版本上做了测试,问题原因可能是Linux内核版 ...

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

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

  3. POSIX线程专有数据的空间释放问题,pthread_key_create

    下面说一下线程中特有的线程存储, Thread Specific Data .线程存储有什么用了?他是什么意思了?大家都知道,在多线程程序中,所有线程共享程序中的变量.现在有一全局变量,所有线程都可以 ...

  4. POSIX 线程详解

    一种支持内存共享的简捷工具 简介: POSIX(可移植操作系统接口)线程是提高代码响应和性能的有力手段.在本系列中,Daniel Robbins 向您精确地展示在编程中如何使用线程.其中还涉及大量幕后 ...

  5. posix线程使用详解

     原文:http://blog.csdn.net/liuhongxiangm/article/details/8308697 Posix多线程编程学习笔记(一)-线程基础(1) 一.什么是线程   ...

  6. POSIX线程的同步

    当线程运行在同样的线程空间,线程们共享同样的内存和资源.这使它变得很容易对于线程来通信和共享数据,尽管它会发生两种问题:线程阻塞和内存不一致由于线程的同步对共享资源的修改.在这些情况下,线程同步变得很 ...

  7. 通用线程:POSIX 线程详解,第 2部分——称作互斥对象的小玩意

    通用线程:POSIX 线程详解,第 2部分--称作互斥对象的小玩意 Daniel Robbins (drobbins@gentoo.org), 总裁/CEO, Gentoo Technologies, ...

  8. posix 线程(一)

    1.POSIX线程库 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以"pthread_"开头,要使用这些函数库,要通过引入头文<pthread.h>,而 ...

  9. linux网络编程之posix线程(二)

    继续接着上次的posix线程来学习: 回顾一下创建线程的函数: pthread_att_t属性变量是需要进行初始化才能够用的,一定初始化了属性变量,它就包含了线程的多种属性的值,那到底有哪些属性了,下 ...

最新文章

  1. 027_自己实现一个ArrayList
  2. 解决ansible报错“msg“: “Failed to import docker-py - cannot import name __version__.
  3. linux脚本ls输出到变量中,bash – 将命令输出的错误消息存储到shell变量中
  4. 《自然》年度十大人物:天才曹原居首 贺建奎来去匆匆
  5. SQLAlchemy orm.query.Query
  6. bootstrap pagewrapper_BootStrap table服务端分页
  7. Python自学笔记-map和reduce函数(来自廖雪峰的官网Python3)
  8. import tool for Scripter Studio
  9. CentOS下常用配置文件和命令以及目录结构备注
  10. python语言程序设计实践教程陈东_20193323实验三《Python程序设计》实验报告
  11. 组合逻辑电路的分析与设计
  12. E+H电磁流量计你知道多少?
  13. 聚沙成塔的分布式云存储
  14. 46、建筑防烟排烟系统的维护保养要求
  15. HTML5自学笔记上
  16. 58同城2014校园招聘软件测试笔试题
  17. x264源码分析与应用示例(一)——视频编码基本流程
  18. 力天创见热区统计方案
  19. MATLAB聚类分析--------2019/8/22
  20. 《2021爱智先行者—精灵1号边缘计算机》

热门文章

  1. CSS中Position定位属性的使用
  2. java8 interface_Java8新特性:函数式接口@FunctionalInterface使用说明
  3. mysql 表名是变量_MySQL深层次的总结
  4. mysql int 判断_PHP通过PDO查MySQL查询int字段返回string类型,解决方案
  5. opencv ubuntu 汉字_OpenCV在ubuntu下的编译
  6. mysql缺失值处理方法,插值MySQL表中的缺失值
  7. Maven和Eclipse整合
  8. VB获取windows各常用目录的函数(模块)
  9. 选课中应用Redis一些思考
  10. Jupyter Notebook的三大短板,都被这个新工具补齐了