可重入函数与不可重入函数的区别
可重入函数:一个函数只访问自己的局部变量或者参数
即同一函数即使被多个执行流同时调用,结果仍然正确。
不可重入函数:一个函数会因访问全局变量而造成错乱
- 首先看下面的例子:
- main函数调用insert函数向链表中插入node1时,插入操作分为两步,可是刚做完第一步的时候因为硬件中断使进程切换到内核,内核进行信号处理时发现处理信号的动作是用户自定义所以再次回到用户态,执行sighandler函数再次插入了一个结点,这时又发生用户态转换为内核态,内核态再次转换为用户态,继续执行main程序流。结果是,链表中先后被插入了两个结点,但最终只有一个结点被真正的插入到结点中。
- 像上面的例子,insert函数流被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱,导致结果错误,像这样的函数称为不可重入函数。
- 反之,如果一个函数只访问自己的局部变量或参数,则称为可重入函数。
不可重入函数的特点
- 调用了malloc或者free
因为malloc也是用全局链表来管理堆的。 - 调用了标准IO库函数。
因为标准IO库的很多函数都以不可重入的方式使用全局数据结构实现的。 - 使用了静态变量或全局变量
- STL容器使用时基本都是不可重入的
可重入函数特点
我们最好使用可重入函数。遵循以下几条规则,写出来的基本就是可重入函数。
- 不要使用全局变量。因为别的代码很可能覆盖这些变量值。
- 在和硬件发生交互的时候,切记执行类似disinterrupt()之类的操作,就是关闭硬件中断。完成交互记得打开中断,在有些系列上,这叫做“进入/退出核心”或者用OS_ENTER_KERNAL/OS_EXIT_KERNAL来描述。//这是临界区保护
- 不能调用任何不可重入的函数。
- 最好使用本地数据,或者通过用本地变量拷贝全局数据从而达到保护全局数据
- 谨慎使用堆栈。最好先在使用前先OS_ENTER_KERNAL。
时刻记住一句话:保证中断是安全的!
可重入的函数一定时线程安全的,但线程安全的函数不一定是可重入的。