深入理解函数线程安全与可重入

1. 函数线程安全

① 函数线程安全基本定义

(1)线程安全:多个线程并发执行同一函数时,不会出现不同的结果,我们就说该函数是线程安全的

(2)线程不安全:如果多线程并发执行同一函数时会产生不同的结果,则称该函数是线程不安全的

注:线程不安全的原因大多说是因为对全局变量和静态变量的操作

② 常见线程不安全函数

(1)不保护共享变量的函数

(2)函数状态随着被调用,状态发生变化的函数

(3)返回指向静态变量指针的函数

(4)调用线程不安全函数的函数

③ 常见线程安全的情况

(1)每个线程对全局变量或者静态变量只有读取的权限,而没有写入的权限,一般来说这些线程是安全的;

(2)类或者接口对于线程来说都是原子操作;

(3)多个线程之间的切换不会导致该接口的执行结果存在二义性;

2. 可重入函数 

① 基本定义

(1)可重入函数:一个可重入的函数简单来说就是可以被中断、且重新进入也不会出错的函数。也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误

(2)不可重入函数:由于使用了一些系统资源,比如全局变量区、中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下

注:可重入函数也可以这样理解,重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外不依赖于任何环境(包括static),这样的函数就是purecode(纯代码)可重入,可以允许有多个该函数的副本在运行,由于它们使用的是分离的栈,所以不会互相干扰

② 可重入函数需要满足的条件

(1)不使用全局变量或静态变量;

(2)不使用malloc或者new开辟出的空间;

(3)不调用不可重入函数

(4)不返回静态或全局数据,所有数据都有函数的调用者提供

(5)使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据

③ 不可重入函数符合以下条件之一

(1)调用了malloc/free函数,因为malloc函数是用全局链表来管理堆的。

(2)调用了标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构

(3)函数体内使用了静态的数据结构

④ 可重入函数分类

(1)显式可重入函数:如果所有函数的参数都是传值传递的(没有指针),并且所有的数据引用都是本地的自动栈变量(也就是说没有引用静态或全局变量),那么函数就是显示可重入的,也就是说不管如何调用,我们都可断言它是可重入的。

(2)隐式可重入函数:可重入函数中的一些参数是引用传递(使用了指针),也就是说,在调用线程小心地传递指向非共享数据的指针时,它才是可重入的。

注:可重入函数可以有多余一个任务并发使用,而不必担心数据错误,相反,不可重入函数不能由超过一个任务所共享,除非能确保函数的互斥(或者使用信号量,或者在代码的关键部分禁用中断)。可重入函数可以在任意时刻被中断,稍后再继续运行,不会丢失数据,可重入函数要么使用本地变量,要么在使用全局变量时保护自己 的数据。

原文地址:https://www.cnblogs.com/wulei0630/p/9506164.html