在多任务系统下,中断可能在任务执行的任何时间发生,同时也可能在任务执行过程中发生系统调度而将执行转向另一个线程,如果一个函数的执行期间被中断后,到重新恢复到断点进行执行的过程中,函数所依赖的环境没有发生改变,那么这个函数就是可重入的,否则就不可重入。
满足下面条件的多数是不可重入的:
(1)使用了静态数据结构;
(2)调用了malloc或free;
(3)调用了标准I/O函数;
(4)进行了浮点运算.
malloc/free是不可重入的,它们使用了全局变量来指向空闲区;标准I/O库的很多实现都使用了全局数据结构; 许多的处理器/编译器中,浮点一般都是不可重入的 (浮点运算大多使用协处理器或者软件模拟来实现)。
linux/unix中的async-signal-safe
知乎上有类似的讨论, linux/unix中可重入的概念一般是要求async-signal-safe,而linux下很多线程安全的函数却都是不可重入的,比如malloc。因为 linux/unix中,signal是以软中断方式分发的,signal handler可能在任何时候打断一个进程的任意线程而执行(如果该线程没有屏蔽该signal的话)。比如在执行某函数A的过程中,signal handler打断线程B中A的执行,然后在线程B的上下文中开始执行处理,在处理中又调用了A,由于A不是异步可重入的,所以会导致严重的问题。
一般情况下可重入会比线程安全更严格一些,因为线程安全是针对多线程而言的:A function that may be safely invoked concurrently by multiple threads。因为可以通过互斥锁等手段使得在多线程环境下对函数的调用得到正确的结果。但如果在函数的调用中嵌套调用了函数自身,可能会因互斥锁而引起死锁,导致函数不可重入。
可重入要求在函数执行过程中被信号中断处理时再次进入该函数之后,调用均可以得到正确的结果。
网友评论