线程安全与可重入

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程安全与可重入相关的知识,希望对你有一定的参考价值。

参考技术A 线程安全问题是由于线程之间存在共享变量(共享资源、临界资源、临界区)引起的。
由于CPU的调度,多个线程访问共享变量从而导致错误的结果,这个在OS、SQL的课程上都有详细的描述。
通常的解决方案就是加锁,以保证一个线程在访问临界区时,其他线程不得访问。

重入是指在调用一个函数且没有返回的情况下再次调用此函数,可重入函数是指一个函数发生重入时,不会导致结果的错误。一般情况下重入是不会发生的(网上很多人将多线程执行同一函数解释为重入,显然这种理解不合适,重入应该是指在单线程的情况下发生的),只有在发生中断、接收到信号的时候才会发生,因此可重入函数一般是对信号处理函数、中断处理函数的要求。

重入会导致结果错误的原因,同线程安全一样也是由于访问共享变量(全局变量,静态变量等)引起的。但是重入的难点在于无法通过加锁解决,因为一旦在加锁后发生重入,就会导致死锁(因为这是在单线程中的)。因此实现可重入的唯一方法就是避免使用任何共享变量。
在调用函数的时候,会在线程的栈中申请一个函数的栈帧,用于执行这个函数,栈帧中存放的是局部变量,因此如果函数中没有共享变量,函数的执行上下文是完全隔离的,这就等价于线程之间没有共享资源,是不会引发任何问题的。

线程安全与可重入编写方法

线程安全与可重入编写方法。

1、什么是线程安全
当一个函数被多个线程反复调用的时候,他会一直产生正确的结果,那么这个函数就是线程安全的。线程安全函数解决了多个线程调用函数时访问临界资源的冲突问题。

2、可重入
在多线程或有异常控制流的情况下,当某个函数运行到中途时,控制流有可能被打断去执行另一个函数,而这”另一个函数”有可能是他本身,如果在这种情况下不会出现问题,比如与说数据或状态不被破坏,而且行为可预期,那么这个函数就被称为可重入的。反之,就是不可重入函数 。
简单来说就是:当一个函数被多个线程调用的时候,不会引用任何共享数据,那么这个函数就是可重入的。可重入函数可以在任意时刻被中断,稍后再继续运行,也不会丢失数据。反之就是不可重入。

3、线程安全与可重入的区别于联系
线程安全的根源就在于”共享数据”。所以不共享任何数据的函数(可重入函数)肯定是线程安全的。但是,即使有共享数据,线程安全还可以通过同步与互斥来保证,所以线程安全并不一定是可重入的。

关系如图:

 

可重入是线程安全的一个真子集,可重入一定线程安全,但线程安全不一定可重入。

4、怎样编写可重入函数
关于线程安全,我们可以通过同步与互斥来实现,下面介绍一下编写可重入函数时的规范:
1、不能在函数内部使用静态或全局数据
2、不能返回静态或全局数据,所有数据都有函数的调用者提供
3、使用本地数据、或通过制作全局数据的本地拷贝来保护全局数据。
4、如果必须访问全局变量,利用互斥机制来保护全局变量。
5、不在可重入函数内部调用不可重入函数。、
6、不调用malloc和free函数,因为malloc是用全局链表来管理堆的。
7、不调用了标准I/O函数。标准I/O函数很多都以不可重入的方式实现全局数据结构。

最常见的就是在信号处理函数中不能使用不可重入函数。如果在信号处理函数中使用了不可重入函数,则可能导致程序出现错误甚至崩溃。

以上是关于线程安全与可重入的主要内容,如果未能解决你的问题,请参考以下文章

线程安全与可重入

线程安全与可重入编写方法

线程安全与可重入函数

线程安全与可重入函数之间的区别

线程安全与可重入函数

对线程安全, 可重入函数, 异步安全的理解