*****可重入函数

函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入。

当程序运行到某一个函数的时候,可能因为硬件中断或者异常而使得在用户正在执行的代码暂时终端转而进入你内核,这个时候如有一个信号需要被处理,而处理的这个信号的时候又会重新调用刚才中断的函数,如果函数内部有一个全局变量需要被操作,那么,当信号处理完成之后重新返回用户态恢复中断函数的上下文再次继续执行的时候,对同一个全局变量的操作结果可能就会发生改变而并不如我们预期的那样,这样的函数被称为不可重入函数。例如在进行链表的插入时,插入函数访问一个全局链表,有可能因为重入而造成错乱。

相对应的,当一个执行流因为异常或者被内核切换而中断正在执行的函数而转为另外一个执行流时,当后者的执行流对同一个函数的操作并不影响前一个执行流恢复后执行函数产生的结果,我们就称这个函数为可重入函数。可重入函数只访问自己的局部变量或参数。其实总结就是:一个可重入函数可以被多个执行流重复进入,内部使用的数据都应该来自于自身的栈空间,包括返回值也不应该是全局或者静态的,可以允许有该函数的多个副本在运行,而正是因为其中的操作数据都来自于自身的栈空间,而每次调用函数会开辟不同的栈空间,因此二者互不影响。

下面为一个不可重入函数的例子:

为了防止这种情况的发生,可以将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、线程安全函数能够使不同的线程访问同一块地址空间,而可重入函数要求不同的执行流对数据的操作不影响结果,使结果是相同的。
---------------------
原文:https://blog.csdn.net/scenlyf/article/details/52074444

Linux可重入函数和线程安全的区别与联系(转)的更多相关文章

  1. 【Linux】可重入函数和线程安全的区别与联系【转】

    转自:http://blog.csdn.net/scenlyf/article/details/52074444 版权声明:本文为博主原创文章,未经博主允许不得转载. *****可重入函数 函数被不同 ...

  2. linux: 可重入函数与不可重入函数

    1. 可重入函数与线程安全 摘自 多线程和多进程的区别(小结) http://blog.csdn.net/hairetz/article/details/4281931 要确保函数线程安全,主要需要考 ...

  3. 可重入函数、线程安全、volatile

    一. POSIX 中对可重入和线程安全这两个概念的定义: Reentrant Function:A function whose effect, when called by two or more  ...

  4. [Linux]不可重入函数

    一.概述 怎么会有可重入和不可重入. 在多任务系统下,中断可能在任务执行的任何时间发生:如果一个函数的执行期间被中断后,到重新恢复到断点进行执行的过程中,函数所依赖的环境没有发生改变,那么这个函数就是 ...

  5. Linux--线程安全与可重入函数的异同

    线程安全 比如一个 ArrayList 类,在添加一个元素的时候,它可能会有两步来完成: 1. 在 Items[Size] 的位置存放此元素: 2. 增大 Size 的值. 在单线程运行的情况下,如果 ...

  6. linux可重入、异步信号安全和线程安全

    一 可重入函数 当一个被捕获的信号被一个进程处理时,进程执行的普通的指令序列会被一个信号处理器暂时地中断.它首先执行该信号处理程序中的指令.如果从信号处理程序返回(例如没有调用exit或longjmp ...

  7. 重读APUE(11)-信号安全的可重入函数

    重入时间点 进程捕捉到信号并对其进行处理时,进程正在执行的正常指令序列就会被信号处理程序临时中断,它首先执行该信号粗合理程序中的指令:如果从信号处理程序返回,则继续执行捕捉到信号时进程正在执行的正常指 ...

  8. linux系统编程之信号(四):alarm和可重入函数

    一,alarm() 在将可重入函数之前我们先来了解下alarm()函数使用: #include <unistd.h> unsigned int alarm(unsigned int sec ...

  9. Use Reentrant Functions for Safer Signal Handling(译:使用可重入函数进行更安全的信号处理)

    Use Reentrant Functions for Safer Signal Handling 使用可重入函数进行更安全的信号处理 How and when to employ reentranc ...

随机推荐

  1. android -------- android studio 中设置创建类时的说明信息(包含 作者 ,创建时间,注释说明等)

    今天简单来说一下android studio开发工具中的 一个小设置功能: 在开发过程中我们习惯给新建的类添加一些注释信息,创建日期.时间和作者等. 设置信息 File—>Settings—&g ...

  2. php 路途一点启示

    wo:  面试了很多说后台不适合女孩,我不相信,而且我还很笨 he:不是立马就能让别人认可你,其中过程要经历很多得,有时候也要换个方式的'' wo: 我只是想用学的知识得到实践 he:那学习的过程不是 ...

  3. oracle数据库静态监听配置示例

    [oracle@Oracle11g admin]$ cat listener.ora SID_LIST_LISTENER =  (SID_LIST =    (SID_DESC =     (GLOB ...

  4. python 小练习2

    给你一个整数列表L,判断L中是否存在相同的数字, 若存在,输出YES,否则输出NO.解1l=[]for i in L:    if L.count(i) != 1:        print('YES ...

  5. TP5+jquery即点既改

    //表单 {volist name="date" id="v"}<tr id="{$v.id}"> <td>< ...

  6. Spring JdbcTemplate 查询出的Map,是如何产生大小写忽略的Key的?(转)

    原文地址:Spring JdbcTemplate 查询出的Map,是如何产生大小写忽略的Key的? 原始讨论组:用Spring JdbcTemplate 查询出的Map,是如何产生大小写忽略的Key的 ...

  7. Java类型中ParameterizedType,GenericArrayType,TypeVariabl,WildcardType详解

    (1). 和反射+泛型有关的接口类型 java.lang.reflect.Type:java语言中所有类型的公共父接口 java.lang.reflect.ParameterizedType java ...

  8. cpu占用过高排查

    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器 内容解释: PID:进程的ID USER:进程所有者 PR:进程的优先级别,越小 ...

  9. mysql查看和修改密码策略

    8.X版本: #查看密码策略 show variables like '%validate_password.policy%'; show variables like '%validate_pass ...

  10. MakeFile中export的使用

    在shell中,可以使用export修改当前进程的环境变量. 例如:export PATH=.:$PATH 将当前路径加入可执行文件查找路径(PATH)中,这样你就不要敲“./excutable” 来 ...