线程安全与不可重入函数

 一.什仫是不可重入函数?

   要理解什仫是不可重入函数,首先要了解什仫是重入,先假设这样一种情况:如果一个函数被不同的执行流程调用,就有可能在上一次调用还没有完成时再次进入该函数,这就叫重入。假设一下如果满足上述条件的函数具有全局变量或者是静态的局部变量,会出现什仫情况呢?下面来看一个关于全局链表头插的情况:

    

    由上图可知当一个函数访问一个全局链表,就有可能因为重入而造成丢失数据,这就叫不可重入函数;相反的,如果一个函数值调用自己的局部变量和函数,则称为可重入函数。

  1.确保一个函数是可重入函数应该满足以下几个条件:

   1).不在函数内部使用静态或者是全局变量
   2).不返回静态或全局数据,数据的产生都由调用者提供
   3).尽量使用本地数据,或者通过重新定义变量拷贝全局变量来保护全局变量
   4).不调用不可重入函数

   可重入函数又分为显氏可重入隐氏可重入

   显式可重入函数:如果所有函数的参数都是传值传递的(没有指针),并且所有的数据引用都是本地的自动栈变量(也就是说没有引用静态或全局变量),那么函数就是显示可重入的,也就是说无论如何调用,我们都可确定它是可重入的。
   隐式可重入函数:可重入函数中的一些参数是引用传递(使用了指针),也就是说,在调用线程的时候传递指向非共享数据的指针时,它才是可重入的。

  2.如果满足以下条件则是不可重入的:

   1).通过malloc和free来申请和释放内存,因为malloc是通过全局链表来管理堆的

   2).调用了标准I/O库,因为库里存在大多数都是以不可重入的方式使用全局变量或者是静态变量

二.什仫是线程安全?线程安全和可重入函数有什仫区别和联系?

  一个函数被称为线程安全的(thread-safe),当且仅当被多个并发进程反复调用时,它会一直产生正确的结果;当然了类似线程安全的栗子,如果一个函数不是线程安全的,我们就说它是线程不安全的(thread-unsafe)。

  上述提到的可重入函数就是线程安全的一种,它的特点就是当被多个线程调用时,不用引起任何共享数据发生变化。根据线程安全的定义可知,任何线程不安全都是因为"共享数据",所以只要不使用任何共享数据的线程一定是安全的。那仫线程安全和可重入函数之间有什仫关系呢?一般来说可重入与线程安全并不等同,如果说可重入函数一定是线程安全的,线程安全的函数却不一定是可重入的,他们之间可用下图来表示:

  

  由上图可知,如果一个函数是可重入函数它一定是线程安全的,相反的如果一个函数是线程安全的它不一定是可重入的。换句话说线程安全 != 可重入,因为即使线程有共享数据,当线程被并发调用时产生的结果也可以是正确的,这种正确就是通过同步机制来保证的。

  1.线程不安全的原因:

  上面已经说过线程不安全主要是因为"共享数据",那仫什仫是共享数据呢?

    1).函数的返回值被一个全局变量所接收

    2).由调用者传入的线程间共享的指针变量或者引用变量

    3).函数内部本来就会使用的共享静态变量

    通常来说,多线程是为了在同一时间内能够处理更多的同样类型的事情,但是线程不安全却阻碍了我们达到我们的目的。所以,我们有的时候不得不想方设法的把线程不安全的函数改写成线程安全的。

  2.如果将一个不安全的线程改写成安全的线程

    1).在使用共享数据的时候可以使用同步机制,在linux中的条件变量可用作同步机制的使用,可参考下文:

http://blog.csdn.net/qq_34328833/article/details/56012780

    2).拒绝使用共享变量,但这个条件是不容易满足的,当一个函数用指针或者引用来接收变量时,是无法保证它是可重入的。

    在这里就分享结束了~~~~


   


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值