看了一会儿,没看懂这个,绝了。书上写的颠三倒四。文档给每个函数两句话。也是没看懂啊!

先把代码试着跑一跑,调试一下,看看结果怎么样。

#include

#include

#include

#include

void cleanup(void *arg)

{

printf("clean...\n");

}

void *My_thread(void *arg)

{

printf("My thread\n");

pthread_cleanup_push(cleanup,"123");

pthread_exit(NULL); //虽然在这里,线程已经结束了,但是下面的pop函数还是得写上。

pthread_cleanup_pop(0);

}

int main()

{

pthread_t tid;

int t = pthread_create(&tid,NULL,My_thread,NULL);

pthread_join(tid,NULL);

return 0;

}

运行结果如下所示:

解释一下,为什么pop函数必须得写上。这是因为它们可以被实现为宏。所以必须在与线程相同的作用域内以匹配的形式使用push函数和pop函数。pthread_cleanup_push的宏定义可以包含字符{,而pthread_cleanup_pop的宏定义必须有相对应的匹配字符}。

在Ubuntu16.04下,pthread_cleanup_push和pthread_cleanup_pop被实现为宏。当我们注释掉pop函数调用之后,再次编译,会发现报错如下:

当你发现这个错误,却无可奈何的时候,你甚至像我一样,检查了好几遍自己的代码。发现没有意料之外的结尾,所有的{}都是成对出现的。殊不知是pthread_cleanup_push和pthread_cleanup_pop被实现为宏。而且含有匹配的{}。

—————————既有趣,又很烦人的坑—————————

下面给出这两个宏的定义,就可以很直观的看到到底是怎么回事。

# define pthread_cleanup_push(routine, arg) \

do { \

__pthread_unwind_buf_t __cancel_buf; \

void (*__cancel_routine) (void *) = (routine); \

void *__cancel_arg = (arg); \

int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *) \

__cancel_buf.__cancel_jmp_buf, 0); \

if (__glibc_unlikely (__not_first_call)) \

{ \

__cancel_routine (__cancel_arg); \

__pthread_unwind_next (&__cancel_buf); \

/* NOTREACHED */ \

} \

\

__pthread_register_cancel (&__cancel_buf); \

do {

extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf)

__cleanup_fct_attribute;

//到这里,pthread_cleanup_push宏定义完了,而这个嵌套的do...while循环没完。

//它还有一半在pthread_cleanup_pop宏之中。

/* Remove a cleanup handler installed by the matching pthread_cleanup_push.

If EXECUTE is non-zero, the handler function is called. */

# define pthread_cleanup_pop(execute) \

do { } while (0);/* Empty to allow label before pthread_cleanup_pop. */\

} while (0); \

__pthread_unregister_cancel (&__cancel_buf); \

if (execute) \

__cancel_routine (__cancel_arg); \

} while (0)

extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf)

__cleanup_fct_attribute;

在此之前,我还是个孩子,从来没有想过宏定义还能这样玩。程序界的前辈又给我上我一课。

好了,言归正传。我们接着看这两个宏到底怎么使用。把线程函数改为如下:

void *My_thread(void *arg)

{

printf("My thread\n");

pthread_cleanup_push(cleanup,"123");

pthread_cleanup_pop(1); //非0参数

pthread_exit(NULL);

}

运行结果如下:

然后继续更改线程函数如下:

void *My_thread(void *arg)

{

printf("My thread\n");

pthread_cleanup_push(cleanup,"123");

pthread_cleanup_pop(0); //0参数

pthread_exit(NULL);

}

运行结果如下:

下面取消线程函数,更改代码如下:

void *My_thread(void *arg)

{

pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); //设置取消线程立即生效

printf("My thread\n");

pthread_cleanup_push(cleanup,"123");

pthread_cancel(pthread_self()); //取消该线程

printf("线程执行不到这里\n");

pthread_cleanup_pop(0); //0参数

}

运行结果如下:

没有打印“线程执行不到这里”这句话。

上述代码中得pthread_self()函数是用来获取正在调用它得线程的ID。而pthread_setcanceltype()函数是用来设置线程取消立即生效的,否则线程取消不是立即生效的。演示如下:

void *My_thread(void *arg)

{

//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);

printf("My thread\n");

pthread_cleanup_push(cleanup,"123");

pthread_cancel(pthread_self());

//sleep(1); //这个取消不是立即生效的,所以加上sleep(1)。也就是说,反正一切小心

printf("线程执行不到这里\n");

//pthread_exit(NULL); //虽然在这里,线程已经结束了,但是下面的pop函数还是得写上。

pthread_cleanup_pop(0); //0参数

// pthread_exit(NULL);

}

运行结果如下:

取消没有立即生效,仍旧打印了“线程执行不到这里”这句话。

既然说到这里了,这个pthread_cancle()函数真是绝了,和这个push,pop宏也差得不多。后面的文章再说这个cancle函数吧。

总结:清理函数是由push函数调度的。

调用pthread_exit()结束线程时;

响应取消线程请求时;

用非0的参数调用pthread_cleanup_pop()时。

当然了,无论什么情况,当pthread_cleanup_pop(0)被调用,那么清理函数将不会起作用。同时需要注意,一个线程可以有多个清理函数。清理程序记录在栈中。因此,一次pop只能取消最近一次的push。这也意味者它们的执行顺序和push注册的顺序是相反的。

本文同步分享在 博客“zy010101”(CSDN)。

如有侵权,请联系 support@oschina.cn 删除。

本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

linux pthread_cleanup_push 线程实现,线程清理(pthread_cleanup_push函数和pthread_cleanup_pop函数)...相关推荐

  1. 5、线程终止方式:pthread_cleanup_push/pthread_cleanup_pop()

    以下内容根据[1]进行整理.关于取消点,将在后面进一步讨论. 1.一般来说,Posix的线程终止有两种情况:正常终止和非正常终止.线程主动调用pthread_exit()或者从线程函数中return都 ...

  2. 【Linux 内核】进程管理 ( 内核线程概念 | 内核线程、普通进程、用户线程 | 内核线程与普通进程区别 | 内核线程主要用途 | 内核线程创建函数 kernel_thread 源码 )

    文章目录 一.内核线程概念 二.内核线程.普通进程.用户线程 三.内核线程.普通进程区别 四.内核线程主要用途 五.内核线程创建函数 kernel_thread 源码 一.内核线程概念 直接 由 Li ...

  3. linux 线程_Linux线程编程专题之线程和线程函数介绍

    ---其实经过这一段时间的Linux应用编程学习,自己总结发现到,在Linux应用编程当中有四大模块我们一定要掌握(这些是最基础的东西): 多进程编程 多线程编程(用的比较多) I/O多路复用 soc ...

  4. pthread_join pthread_exit 线程 Linux函数 线程退出 线程等待

    接下来我们看一下线程退出函数和等待函数. #include <pthread.h> void pthread_exit(void *value_ptr); value_ptr:是线程的返回 ...

  5. 关于linux的进程和线程

    关于linux的进程和线程 http://kenby.iteye.com/blog/1014039 Linux下的多线程编程 http://fanqiang.chinaunix.net/a4/b8/2 ...

  6. LINUX线程及线程间通信

    线程概念 什么是线程 LWP:light weight process 轻量级的进程,本质仍是进程(在Linux环境下) 进程:独立地址空间,拥有PCB(进程控制块PCB(Process Contro ...

  7. Windows和Linux下通用的线程接口

    对于多线程开发,Linux下有pthread线程库,使用起来比较方便,而Windows没有,对于涉及到多线程的跨平台代码开发,会带来不便.这里参考网络上的一些文章,整理了在Windows和Linux下 ...

  8. linux 线程--内核线程、用户线程实现方法

    Linux上进程分3种,内核线程(或者叫核心进程).用户进程.用户线程 内核线程拥有 进程描述符.PID.进程正文段.核心堆栈 当和用户进程拥有相同的static_prio 时,内核线程有机会得到更多 ...

  9. Multi-thread--Windows和Linux下通用的线程接口

    对于多线程开发,Linux下有pthread线程库,使用起来比较方便,而Windows没有,对于涉及到多线程的跨平台代码开发,会带来不便.这里参考网络上的一些文章,整理了在Windows和Linux下 ...

  10. linux 指定cpu运行线程,linux 线程与CPU绑定

    看到很多程序都是根据CPU个数来创建线程个数,当时很不理解他们之间的关系,请教了项目组的同事后才有了大致了解. 1. 相关系统函数 下面的函数可以通过man命令查询到.SYNOPSIS #define ...

最新文章

  1. 机器人流程自动化(RPA)系统原理及特点
  2. “32 位应用已死!”
  3. Waymo起诉加州车管所,要求对无人车事故数据保密,网友:这事怕不是和特斯拉有关...
  4. Openstack组建部署 — Glance Install
  5. 开课吧python课程-明星为开课吧直播带货:人人都要学,人人都可以学的Python
  6. 实至名归!ACM宣布深度学习三巨头共同获得图灵奖
  7. 杭电1241java实现dfs
  8. 情感分析的现代方法(包含word2vec Doc2Vec)
  9. 由web项目中上传图片所引出的路径问题
  10. python模块搜索原则_详解python模块路径查找规则及定义
  11. 找不到合适的创业路该怎么办
  12. APACHE OFBIZ XML-RPC 反序列化漏洞 (CVE-2020-9496) 的复现与分析
  13. 开放集合目标检测任务 Open-set Detection
  14. DeepFaceLab
  15. 鼠标键盘的使用:用左ALT+左SHIFT+NUM LOCK即可启动或关闭键盘的鼠标键
  16. Windows 7 频繁提示:计算机的内存不足
  17. 计算机中基本磁盘分为几个区,电脑硬盘分几个区最好?电脑硬盘分区教程
  18. matlab面元法计算naca翼型的升力系数(关于攻角的曲线)
  19. 2019年3月最新windwows101809教育版激活密钥及其下载地址
  20. c语言指针关键字,C语言关键字const和指针的结合使用

热门文章

  1. 读取csv(excel类相关文件)常见bug,及解决办法统计
  2. openfire 群聊 java_Openfire即时通讯群聊、单聊、登录、注销的使用方法(Java+Android)...
  3. S3C2440裸机------内存控制器
  4. 联想笔记本e43l_联想昭阳e43l
  5. 纵横算法之四:算法应该怎么学
  6. 人工智能与商业智能,区别、定位与联系
  7. 商业智能的研究,主要集中在哪三个方面?
  8. c语言报刊杂志订阅系统,C杂志订阅管理系统.doc
  9. mrc mcr 与 bic orr 含义及用法示例
  10. 前端面试,面试官会问些啥...