回顾
什么是可重入?
上一篇: 可重入和不可重入
线程安全函数
如果一个函数,对于多个线程来说是可重入的,那么这个函数就是线程安全的
异步信号安全
如果函数对于异步信号处理成序的重入是安全的,那么该函数就是异步信号安全的
包含关系
可重入与线程安全两个概念都关系到函数处理资源的方式。但是,他们有重大区别:
-
可重入函数要解决的问题是,不在函数内部使用静态或全局数据,不返回静态或全局数据,也不调用不可重入函数。
-
线程安全函数要解决的问题是,多个线程调用函数时访问资源冲突。
① : 函数如果使用静态变量,通过加锁后可以转成线程安全函数,但仍然有可能不是可重入的,比如strtok
strtok是既不可重入的,也不是线程安全的。
加锁的strtok不是可重入的,但线程安全。
而strtok_r既是可重入的,也是线程安全的。
区别和联系
- 可重入是对函数相当严格的要求,绝大部分函数都不是可重入的(APUE上有一个reentrant函数的列表).
什么时候我们需要reentrant函数呢?
只有一个函数需要在同一个线程中需要进入两次以上,我们才需要
reentrant函数.这些情况主要是异步信号处理,递归函数等等.(non-reentrant的递归函数也不一定会
出错,出不出错取决于你怎么定义和使用该函数). 大部分时候,我们并不需要函数是reentrant的.
-
在多线程环境当中,只要求多个线程可以同时调用一个函数时,该函数只要是线程安全的就可以了.
-
可重入和线程安全的本质的区别就在于,可重入函数要求即使在同一个线程中任意地进入两次以上,也能正确执行.
大家常用的malloc函数是一个典型的non-reentrant但是是thread safe函数,这就说明,我们可以方便的
在多个线程中同时调用malloc,但是,如果将malloc函数放入信号处理函数中去,这是一件很危险的事情.
- 可重入函数一般(网上说法很多,但最起码我没见过反例)都是线程安全函数.
不能简单的通过加锁,来使得non-reentrant函数变成 reentrant函数
"使用的全局变量的函数也不一定是不可重入的。"
这句是正确的,只要正确使用就可以了,但是不使用全局变量是写可重入函数的简单方法.
"调用了不可重入函数的函数不一定是不可重入的。"
这句是不对的,因为你无法保证被调用的不可重入函数部分不被重入
如图所示: