线程安全和可重入函数

一,什么是线程安全?

1,线程安全就是说多线程访问同一代码,不会产生不确定的结果。换句话说,线程安全就是多线程访问时,采用加锁机制,当一个线程访问该类的某个数据时,用锁对数据进行保护,其他线程不能访问该数据直到该线程读取完,其他线程才可使用,线程安全不会出现数据不一致或者数据污染。反之, 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。

二,什么是可重入函数?

这里写图片描述
    图中,main函数调用insert函数向一个链表head中插入节点node1,由于插入操作分为两步,刚做完第一步的时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到sighandler函数,sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作的两步都做完之后从sighandler返回内核态,再次回到用户态就从main函数调用的insert函数中继续 往下执行,先前做第一步之后被打断,现在继续做完第二步。结果是,main函数和sighandler先后向链表中插入两个节点node1和node2,而最后node1真正插入链表了,node2丢失导致内存泄漏。

像上例这样,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函 数,这称为重入。
insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为不可重入函数,反之,如果一个函数只访问自己的局部变量或参数,则称为可重入函数(Reentrant)。

2,重入函数 (分为可重入和不可重入函数) 的本质:两个不同的控制流程调用了全局堆中的共享数据,如果函数中都是局部变量则没有重入问题。

可重入函数需要满足的是:
1、不使用全局变量或静态变量;
2、不使用用malloc或者new开辟出的空间;
3、不调用不可重入函数;
4、不返回静态或全局数据,所有数据都有函数的调用者提供;
5、使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据;

如果一个函数符合以下条件之一则是不可重入的:
1>调用了malloc或free,因为malloc也是用全局链表来管理堆的。
2>调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。
3>SUS规定有些系统函数必须以线程安全的方式实现。

三,线程安全与可重入函数的区别与联系

这里写图片描述
函数可以是可重入的,也可以是线程安全的,或者两者皆是,或者两者皆非。不可重入函数不能由多个线程使用。

1、线程安全是在多线程情况下引发的,而可重入函数可以在只有一个线程的情况下发生。
2、线程安全不一定是可重入的,而可重入函数则一定是线程安全的。
3、如果一个函数有全局变量,则这个函数既不是线程安全也不是可重入的。
4、如果一个函数当中的数据全身自身栈空间的,则这个函数即使线程安全也是可重入的。
5、如果将对临界资源的访问加锁,则这个函数是线程安全的;但如果重入函数的话加锁还未释放,则会产生死锁,因此不能重入。
6、线程安全函数能够使不同的线程访问同一块地址空间,而可重入函数要求不同的执行流对数据的操作不影响结果,使结果是相同的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值