加强学院网站的建设与管理,网站的开发是使用什么技术,西安网站 建设,如何重置wordpress文章目录 可重入与线程安全的关系 可重入
若一个程序或子程序可以“在任意时刻被中断然后操作系统调度执行另一段代码#xff0c;这段代码又使用了该副程序不会出错”#xff0c;则称其为可重入#xff08;reentrant 或 re-entrant#xff09;的。即当该副程序正在运作时这段代码又使用了该副程序不会出错”则称其为可重入reentrant 或 re-entrant的。即当该副程序正在运作时执行线程可以再次进入并执行它仍然可得到符合设计时所预期的结果。与多线程并发执行的线程安全不同可重入强调对单一线程执行时重新进入同一个子程序仍然是安全的。
若一个函数是可重入的则该函数应当满足下述条件 不能含有静态全局非常量数据。 不能返回静态全局非常量数据的地址。 只能处理由调用者提供的数据。 不能依赖于单例模式资源的锁。 调用call的函数也必需是可重入的。 上述条件就是要求可重入函数使用的所有变量都保存在调用堆栈的目前函数栈frame上因此同一执行线程重入执行该函数时加载了新的函数帧与前一次执行该函数时使用的函数帧不冲突、不互相覆盖从而保证了可重入执行安全。
例子 在以下的C语言代码中函数f和函数g都不是可重入的。 int g_var 1;int f(){g_var g_var 2;return g_var;}int g(){return f() 2;}以上代码中f使用了全局变量 g_var所以如果两个线程同时执行它并访问g_var则返回的结果取决于执行的时间。因此f不可重入。而g调用了f所以它也不可重入。
稍作修改后两个函数都是可重入的 int f(int i){return i 2;}int g(int i){return f(i) 2;}与线程安全的关系
游双Linux书96函数是不可重入即非线程安全应该表述有一些问题。
可重入与线程安全两个概念都关系到函数处理资源的方式。但是他们有重大区别
可重入概念会影响函数的外部接口而线程安全只关心函数的实现。 大多数情况下要将不可重入函数改为可重入的需要修改函数接口使得所有的数据都通过函数的调用者提供。 要将非线程安全的函数改为线程安全的则只需要修改函数的实现部分。一般通过加入同步机制以保护共享的资源使之不会被几个线程同时访问。 操作系统背景与CPU调度策略 可重入是在单线程操作系统背景下重入的函数或者子程序按照后进先出的线性序依次执行完毕。 多线程执行的函数或子程序各个线程的执行时机是由操作系统调度不可预期的但是该函数的每个执行线程都会不时的获得CPU的时间片不断向前推进执行进度。 可重入函数未必是线程安全的线程安全函数未必是可重入的。 例如一个函数打开某个文件并读入数据。这个函数是可重入的因为它的多个实例同时执行不会造成冲突但它不是线程安全的因为在它读入文件时可能有别的线程正在修改该文件为了线程安全必须对文件加“同步锁”。 另一个例子函数在它的函数体内部访问共享资源使用了加锁、解锁操作所以它是线程安全的但是却不可重入。因为若该函数一个实例运行到已经执行加锁但未执行解锁时被停下来系统又启动该函数的另外一个实例则新的实例在加锁处将转入等待。如果该函数是一个中断处理服务在中断处理时又发生新的中断将导致资源死锁。fprintf函数就是线程安全但不可重入。
下述例子是线程安全的但不是可重入的。
int function()
{mutex_lock();...function body...mutex_unlock();
}多线程执行时获得了互斥锁的线程总能获得CPU时间片向前推进执行进度最终解开互斥锁使得别的线程也能获得互斥锁进入临界区。但是如果在单线程背景下第一次执行该函数时已经获得互斥锁进入临界区这时该函数被重入执行这将在重新申请互斥锁时被饿死(starvation)因为获得了互斥锁的该函数的第一次执行将永远没有机会再获得CPU时间片。