【Linux】可重入函数和线程安全的区别与联系【转】
转自:http://blog.csdn.net/scenlyf/article/details/52074444
版权声明:本文为博主原创文章,未经博主允许不得转载。
*****可重入函数
函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入。
当程序运行到某一个函数的时候,可能因为硬件中断或者异常而使得在用户正在执行的代码暂时终端转而进入你内核,这个时候如有一个信号需要被处理,而处理的这个信号的时候又会重新调用刚才中断的函数,如果函数内部有一个全局变量需要被操作,那么,当信号处理完成之后重新返回用户态恢复中断函数的上下文再次继续执行的时候,对同一个全局变量的操作结果可能就会发生改变而并不如我们预期的那样,这样的函数被称为不可重入函数。例如在进行链表的插入时,插入函数访问一个全局链表,有可能因为重入而造成错乱。
相对应的,当一个执行流因为异常或者被内核切换而中断正在执行的函数而转为另外一个执行流时,当后者的执行流对同一个函数的操作并不影响前一个执行流恢复后执行函数产生的结果,我们就称这个函数为可重入函数。只访问自己的局部变量或参数。其实总结就是:一个可重入函数可以被多个执行流重复进入,内部使用的数据都应该来自于自身的栈空间,包括返回值也不应该是全局或者静态的,可以允许有该函数的多个副本在运行,而正是因为其中的操作数据都来自于自身的栈空间,而每次调用函数会开辟不同的栈空间,因此二者互不影响。
下面为一个不可重入函数的例子:
为了防止这种情况的发生,可以将g_val改为局部变量。这样函数两次被调用的时候,两次结果最终并不影响且相等,函数变为可重入函数了。
可重入函数的分类
(1)显式可重入函数
如果所有函数的参数都是传值传递的(没有指针),并且所有的数据引用都是本地的自动栈变量(也就是说没有引用静态或全局变量),那么函数就是显示可重入的,也就是说不管如何调用,我们都可断言它是可重入的。
(2)隐式可重入函数
可重入函数中的一些参数是引用传递(使用了指针),也就是说,在调用线程小心地传递指向非共享数据的指针时,它才是可重入的。
可重入函数可以有多余一个任务并发使用,而不必担心数据错误,相反,不可重入函数不能由超过一个任务所共享,除非能确保函数的互斥(或者使用信号量,或者在
代码的关键部分禁用中断)。可重入函数可以在任意时刻被中断,稍后再继续运行,不会丢失数据,可重入函数要么使用本地变量,要么在使用全局变量时保护自己
的数据。
一个可重入函数需要满足的是:
1、不使用全局变量或静态变量;
2、不使用用malloc或者new开辟出的空间;
3、不调用不可重入函数;
4、不返回静态或全局数据,所有数据都有函数的调用者提供;
5、使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据;
不可重入函数符合以下条件之一:
1、调用了malloc/free函数,因为malloc函数是用全局链表来管理堆的。
2、调用了标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构。
3、可重入体内使用了静态的数据结构。
*****线程安全的概念
一个函数被称为线程安全的(thread-safe),当且仅当被多个并发进程反复调用时,它会一直产生正确的结果。反之,如果一个函数不是线程安全的,我们就说它是线程不安全的(thread-unsafe)。所以,有这么四类函数称为线程不安全的:
1、不保护共享变量的函数;
2、函数状态随着调用改变的函数;
3、返回指向静态变量指针的函数;
4、调用线程不安全函数的函数;
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。或者说一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。一般来说,一个函数被称为线程安全的,当且仅当被多个并发线程反复调用时,它会一直产生正确的结果。
根据线程的同步与互斥,也就是当两个线程同时访问到同一个临界资源的时候,如果
发现上述结果中所得结果不是1000,并且多次运行结果都不同,因此此程序线程是不安全的。
因此,线程安全是指当多个线程访问同一个区域的时候其最终的结果是可预期的,并不会因为产生冲突或者异常中断再次恢复而使结果不可预期。
*****可重入函数与线程安全的区别与联系
函数可以是可重入的,也可以是线程安全的,或者两者皆是,或者两者皆非。不可重入函数不能由多个线程使用。
1、线程安全是在多线程情况下引发的,而可重入函数可以在只有一个线程的情况下发生。
2、线程安全不一定是可重入的,而可重入函数则一定是线程安全的。
3、如果一个函数有全局变量,则这个函数既不是线程安全也不是可重入的。
4、如果一个函数当中的数据全身自身栈空间的,则这个函数即使线程安全也是可重入的。
5、如果将对临界资源的访问加锁,则这个函数是线程安全的;但如果重入函数的话加锁还未释放,则会产生死锁,因此不能重入。
6、线程安全函数能够使不同的线程访问同一块地址空间,而可重入函数要求不同的执行流对数据的操作不影响结果,使结果是相同的。
【Linux】可重入函数和线程安全的区别与联系【转】的更多相关文章
- Linux可重入函数和线程安全的区别与联系(转)
*****可重入函数 函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入. 当程序运行到某一个函数的时候,可能因为硬件中断或者异常而使得在用户正在执行的代码暂时终端转而 ...
- linux: 可重入函数与不可重入函数
1. 可重入函数与线程安全 摘自 多线程和多进程的区别(小结) http://blog.csdn.net/hairetz/article/details/4281931 要确保函数线程安全,主要需要考 ...
- 可重入函数、线程安全、volatile
一. POSIX 中对可重入和线程安全这两个概念的定义: Reentrant Function:A function whose effect, when called by two or more ...
- [Linux]不可重入函数
一.概述 怎么会有可重入和不可重入. 在多任务系统下,中断可能在任务执行的任何时间发生:如果一个函数的执行期间被中断后,到重新恢复到断点进行执行的过程中,函数所依赖的环境没有发生改变,那么这个函数就是 ...
- Linux--线程安全与可重入函数的异同
线程安全 比如一个 ArrayList 类,在添加一个元素的时候,它可能会有两步来完成: 1. 在 Items[Size] 的位置存放此元素: 2. 增大 Size 的值. 在单线程运行的情况下,如果 ...
- linux可重入、异步信号安全和线程安全
一 可重入函数 当一个被捕获的信号被一个进程处理时,进程执行的普通的指令序列会被一个信号处理器暂时地中断.它首先执行该信号处理程序中的指令.如果从信号处理程序返回(例如没有调用exit或longjmp ...
- 重读APUE(11)-信号安全的可重入函数
重入时间点 进程捕捉到信号并对其进行处理时,进程正在执行的正常指令序列就会被信号处理程序临时中断,它首先执行该信号粗合理程序中的指令:如果从信号处理程序返回,则继续执行捕捉到信号时进程正在执行的正常指 ...
- linux系统编程之信号(四):alarm和可重入函数
一,alarm() 在将可重入函数之前我们先来了解下alarm()函数使用: #include <unistd.h> unsigned int alarm(unsigned int sec ...
- Use Reentrant Functions for Safer Signal Handling(译:使用可重入函数进行更安全的信号处理)
Use Reentrant Functions for Safer Signal Handling 使用可重入函数进行更安全的信号处理 How and when to employ reentranc ...
随机推荐
- 解决Linux使用php命令 -base comment not found并安装composer
获取php的安装目录 使用 find / -name php.ini 查看php的安装位置 /usr/local/php/lib/php.ini # cd 到/usr/local/php/lib/ph ...
- ubuntu版本查看
cat /proc/version uname -a lsb_release -a
- linux 查看CPU内存 网络 流量 磁盘 IO
使用vmstat命令来察看系统资源情况 在命令行方式下,如何查看CPU.内存的使用情况,网络流量和磁盘I/O? Q: 在命令行方式下,如何查看CPU.内存的使用情况,网络流量和磁盘I/O? A: 在命 ...
- 笔记-python-standard library-9.6 random
笔记-python-standard library-9.6 random 1. random source code:Lib/random.py 1.1. functions for ...
- git pull免密码拉取
ssh到服务器上,原来基于public/private key pair的方法不好使了. 1.1 创建文件存储GIT用户名和密码 在%HOME%目录中,一般为C:\users\Administrato ...
- MySQL基础7-分页查询
1.分页查询(MySQL特有的,oracle中没有) 栗子1: 每页最多3条记录:pageSize=3:第一页:SELECT * FROM product LIMIT 0,3第二页:SELECT * ...
- day14 前端基础 HTML
从今天开始,学习前端基础. 前端,就是HTML CSS JS 等 对于我们这种初学者,并不知道这些专业术语都是什么,给大家举一个形象的例子: HTML 就是一个人,赤裸裸的人 CSS 就是衣服 ...
- Python面向对象之什么是类(1)
1.C#.Java :只能用面向对象编程 Ruby.Python :函数编程+ 面向对象 面向对象编程不是在所有地方都比函数式编程方便的,类是为了封装,下面是简单的使用方法 在创建类的时候要用clas ...
- DWR搭建以及使用教程
DWR搭建以及使用教程 DWR(Direct Web Remoting)是一个Ajax的开源框架,用于改善web页面与Java类交互的远程服务器端的交互体验,可以帮助开发人员开发包含AJAX技术的 ...
- 【bzoj3630】[JLOI2014]镜面通道 对偶图+计算几何+网络流最小割
题目描述 在一个二维平面上,有一个镜面通道,由镜面AC,BD组成,AC,BD长度相等,且都平行于x轴,B位于(0,0).通道中有n个外表面为镜面的光学元件,光学元件α为圆形,光学元件β为矩形(这些元件 ...