linux高级编程之线程间的通信(pthread_cleanup_push和pthread_cleanup_pop)

线程可以安排他退出时需要调用的函数,这与进程可以用atexit函数安排进程退出时需要调用的函数是类似的。这样的函数称为线程清理处理程序,线程可以建立多个清理处理程序。处理程序记录在栈中,也就是说他们的执行顺序与他们注册的顺序相反。

pthread_cleanup_push和pthread_cleanup_pop函数原型如下:

头文件:#include <pthread.h>

函数原型:void pthread_cleanup_push(void (*rtn)(void *), void *arg);

void pthread_clean_pop(int execute);

void(*rtn)(void *): 线程清理函数

另外简单记录下pthread_cancel函数。该函数为线程取消函数,用来取消同一进程中的其他进程,函数原型:

头文件: #include <pthread.h>

函数原型:pthread_cancel(pthread_t tid);

tid: 线程id

当线程执行以下动作时,调用清理函数,调用的参数为arg,清理函数rtn的调用顺序是由pthread_cleanup_push函数来安排的。

●调用pthread_exit时

●响应取消请求时

●用非零execute参数调用pthread_cleanup_pop时

关于书上有句原话:“如果execute参数置为0,清理函数将不被调用”,我觉得说的有问题,而且接下来我摘抄了书上的一个例子,刚好验证了他说的这句话的错误,而且我也验证了下,当然在一篇博客中我看到这样的解释觉得很合理:当pthread_cleanup_pop()函数的参数为0时,仅仅在线程调用pthread_exit函数或者其它线程对本线程调用 pthread_cancel函数时,才在弹出“清理函数”的同时执行该“清理函数”。同样我也取了博客中的第二个例子来说明pthread_cancel调用时,pthread_cleanup_push会用清理函数。(ps:重新看了下这个疑问,翻书看了下,其实后面还有句话:“不管上述哪种情况,pthread_cleanup_pop都将删除上次pthread_cleanup_push调用建立的清理函数”,所以可能作者想表达的是设置为pop参数设置为0,在其它两种情况下同样会被调用)

参考博客:http://blog.chinaunix.net/uid-26772137-id-3369725.html

例1:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> void cleanup(void *arg)
{
printf("cleanup:%s\n",(char*)arg);
}
void *thr_fn1(void *arg)
{
printf("thread 1 start\n");
pthread_cleanup_push(cleanup,"thread 1 first handler");
pthread_cleanup_push(cleanup,"thread 1 second handler");
printf("thread 1 push complete\n");
if(arg)
return ((void *)1);
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return ((void *)1);
}
void *thr_fn2(void *arg)
{
printf("thread 2 start\n");
pthread_cleanup_push(cleanup,"thread 2 first handler");
pthread_cleanup_push(cleanup,"thread 2 second handler");
printf("thread 2 push complete\n");
if(arg)
pthread_exit((void *)2);
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
pthread_exit((void *)2);
}
int main()
{
int err;
pthread_t tid1,tid2;
void *tret;
err = pthread_create(&tid1,NULL,thr_fn1,(void *)1);
if(err != 0)
{
fprintf(stderr,"thread create 1 is error\n");
return -1;
}
err = pthread_create(&tid2,NULL,thr_fn2,(void *)1);
if(err != 0)
{
fprintf(stderr,"thread create 2 is error\n");
return -2;
}
err = pthread_join(tid1,&tret);
if(err != 0)
{
fprintf(stderr,"can't join with thread 1\n");
return -2;
} //pthread_cancel(tid1);
printf("thread 1 exit code %d\n",tret);
err = pthread_join(tid2,&tret);
if(err != 0)
{
fprintf(stderr,"can't join with thread 2\n");
return -2;
}
printf("thread 2 exit code %d\n",tret);
return 0;
}

运行结果如下:

从输出结果可以看出:两个线程都调用了,但是却只调用了第二个线程的清理处理程序,所以如果线程是通过从它的启动历程中返回而终止的话,那么它的清理处理程序就不会被调用,还要注意清理程序是按照与它们安装时相反的顺序被调用的。从代码输出也可以看到先执行的thread 2 second handler后执行的thread 2 first handler。

例2:

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
void clean_fun1(void * arg)
{
printf("this is clean fun1\n");
}
void clean_fun2(void * arg)
{
printf("this is clean fun2\n");
}
void * thread_fun(void * arg)
{
pthread_cleanup_push(clean_fun1,NULL);
pthread_cleanup_push(clean_fun2,NULL);
sleep(100);
//这里要注意,如果将sleep(100);换成while(1);的话,程序会一直暂停.push和pop要成对出现.
//因为while(1);运行的太快,线程不接受cancel信号
//while(1);
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return NULL;
}
int main()
{
pthread_t tid1;
int err;
err=pthread_create(&tid1,NULL,thread_fun,NULL);
if(err!=0)
{
perror("pthread_create");
exit(0);
}
sleep(3);
//printf("test\n");
err=pthread_cancel(tid1);
if(err!=0)
{
perror("cancel error:");
exit(0);
}
err=pthread_join(tid1,NULL);
if(err!=0)
{
perror("pthread_join error:");
exit(0);
} return 0;
}

运行结果如下:

从上面也可以看出,当调用pthread_cancel函数请求后,等到响应请求时,代码调用了pthread_clean_push函数中的clean_fun1和clean_fun2,函数clean_fun2中的语句先被打印。

linux高级编程之线程间的通信(pthread_cleanup_push和pthread_cleanup_pop)的更多相关文章

  1. iOS多线程编程之线程间的通信(转载)

    一.简单说明 线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个线程传递数据给另1个线程 在1个线程中执行完特定任务后,转到另1个线程继续执行任务 ...

  2. Linux高级编程--09.线程互斥与同步

    多个线程同时访问共享数据时可能会冲突,比如两个线程都要把某个全局变量增加1,这个操作在某平台需要三条指令完成: 从内存读变量值到寄存器 寄存器的值加1 将寄存器的值写回内存 假设两个线程在多处理器平台 ...

  3. Linux高级编程--08.线程概述

    线程 有的时候,我们需要在一个基础中同时运行多个控制流程.例如:一个图形界面的下载软件,在处理下载任务的同时,还必须响应界面的对任务的停止,删除等控制操作.这个时候就需要用到线程来实现并发操作. 和信 ...

  4. linux高级编程基础系列:线程间通信

    linux高级编程基础系列:线程间通信 转载:原文地址http://blog.163.com/jimking_2010/blog/static/1716015352013102510748824/ 线 ...

  5. Java多线程编程(6)--线程间通信(下)

      因为本文的内容大部分是以生产者/消费者模式来进行讲解和举例的,所以在开始学习本文介绍的几种线程间的通信方式之前,我们先来熟悉一下生产者/消费者模式.   在实际的软件开发过程中,经常会碰到如下场景 ...

  6. Java多线程编程核心技术---线程间通信(二)

    通过管道进行线程间通信:字节流 Java提供了各种各样的输入/输出流Stream可以很方便地对数据进行操作,其中管道流(pipeStream)是一种特殊的流,用于在不同线程间直接传送数据,一个线程发送 ...

  7. Java多线程编程核心技术---线程间通信(一)

    线程是操作系统中独立的个体,但这些个体如果不经过特殊处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一.线程间通信可以使系统之间的交互性更强大,在大大提高CPU利用率的同时还会使程序员对各 ...

  8. 并发编程系列小结(线程安全,synchronized,脏读,线程间的通信wait/notify,线程的三种实现方式Demo,可替代wait/notify的方法)

    线程安全: 当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法就是线程安全的) synchronized: 可以在任意对象或方法上加锁,而加锁的这段代码称为 ...

  9. Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  10. Win32多线程编程(3) — 线程同步与通信

      一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线 ...

随机推荐

  1. c语言数据结构 树的基本操作

    树的基本操作有创建,插入,删除,以及各种遍历的应用,如:利用后序遍历求高度,利用前序遍历求层数的结点 基本算法思路:创建二叉树函数参数必须接受二级指针!如果使用同级指针,无法返回创建后的结果,利用递归 ...

  2. Sqoop导入MySQL表中数据到Hive出现错误: ERROR hive.HiveConfig: Make sure HIVE_CONF_DIR is set correctly.ERROR tool.ImportTool: Import failed:

    1.问题描述: (1)问题示例: [Hadoop@master TestDir]$ sqoop import --connect jdbc:mysql://master:3306/source?use ...

  3. 使用Python+Appium+夜神模拟器,并连接uiautomatorviewer

    本文不介绍安装步骤,实在是太多博文了 一.安装 Python:3.8 Appium:1.22.3 夜神模拟器 node JDK1.8 SDK 二.成功连接模拟器 PytCharm代码如下: # cod ...

  4. 关系类处理专题之创建关系类|RelationShipClass

    /// <summary> /// 存在于数据库中的数据集中 /// </summary> /// <param name="mdbPath"> ...

  5. MySql8错误记录.巨坑!File './binlog.index' not found

    mysql8存在大小写敏感,若要设置不敏感,需要在mysql初始化时设置:然后库中已有项目存在,mysql备份文件夹后无法重启,还原数据后存在权限问题,更改文件夹权限后,发现仍然不行,将SELinux ...

  6. Django笔记二之连接数据库、执行migrate数据结构更改操作

    本篇笔记目录索引如下: Django 连接mysql,执行数据库表结构迁移步骤介绍 操作数据库,对数据进行简单操作 接下来几篇笔记都会介绍和数据库相关,包括数据库的连接.操作(包括增删改查).对应的字 ...

  7. 商城网站毕业设计( Python +Vue)

    网站介绍 基于 python 开发的电子商城网站,平台采用 B/S 结构,后端采用主流的 Python 语言进行开发,前端采用主流的 Vue.js 进行开发.这是给师弟开发的毕业设计. 整个平台包括前 ...

  8. odoo 开发入门教程系列-模型和基本字段

    模型和基本字段 在上一章的末尾,我们创建一个odoo模块.然而,此时它仍然是一个空壳,不允许我们存储任何数据.在我们的房地产模块中,我们希望将与房地产相关的信息(名称(name).描述(descrip ...

  9. pta第一到第三次题目集

    (1)前言 pta第一次作业的7-1,7-2,7-4主要熟悉运用了 if-else 的语句使用,以及运用System.out.printf进行格式化输出,7-3九九乘法表主要学会了运用for循环及多重 ...

  10. Conda in Windows under MSYS2 and Zsh 的问题解决

    Conda in Windows under MSYS2 and Zsh 的问题解决 在Window11上使用git bash 安装zsh,并配置p10k主题,主要问题就是prompt中无法显示con ...