可重入函数与线程安全

重入:当不同的控制流程调用同一个函数时,有可能当一个调用还没返回时,另一个调用就进入了该函数,将其称作重入;

不可重入函数:当一个函数由于可重入出错,则将此函数称为不可重入函数;

可重入函数:当一个函数由于可重入而不影响各自流程的正确结果(其只访问自己的局部变量和参数),将此函数称作可重入函数;

举例:常见情况中,当程序正在执行到某一个函数中的某一条指令时,这时其收到了一个信号,于是其暂停执行去处理信号,执行此信号的处理动作,而这个信号处理动作的函数正好为刚刚执行到函数,于是就对此函数造成了可重入,而当信号处理动作执行此函数正确运行,程序返回时之前暂停执行的此函数也能正确运行,则将此函数称为可重入函数。

注意:重入前提条件是不同的控制流程访问同一个函数,而信号处理函数和main函数正是使用不同的堆栈空间,它们之间不存在调用和被调用的关系,就是两个独立的控制流程。

确保可重入函数的必要条件如下:

(1)不在函数内部使用静态和全局数据(由于进程不同的控制流程访问共享数据会造成数据错乱);

(2)不调用malloc或free,因为malloc也是用全局链表来管理堆的;

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

(4)不调用不可重入函数;

(5)不能返回静态和全局数据,所有数据都由函数的调用者提供;

(6)使用本地数据、或通过制作全局数据的本地拷贝来保护全局数据;

(7)若必须访问全局数据,利用互斥机制保护全局数据;

(8)不使用静态的数据结构。

可重入函数特点:

(1)可重入函数调用多次不会出错,其不用担心数据被破坏;

(2)可重入函数在任意时刻被中断,一段时间恢复,其数据不会丢失;

(3)只使用局部变量,保存在CPU寄存器或栈中,或者使用全局变量但会予以保护。


线程安全:

若一个函数被称为线程安全的,当且仅被多个并发线程反复调用时,它会一直产生正确的结果。

确保线程安全:

确保线程安全,主要考虑线程之间的共享数据,属于同一个进程之间的线程会共享进程内存空间的全局区和堆,而其私有的主要为栈空间、上下文(寄存器等),所以对于每个线程其局部变量是私有的,全局变量、局部静态变量、全局静态变量、分配与堆的变量都是共享的,若对这些共享数据访问时,确保其线程安全,则必须通过加锁等方式使线程间互斥的访问,不然必定造成数据的错乱,如共享数据的值由于不同线程的访问发生变化产生不可预料的后果,可能导致整个进程异常。


可重入函数与线程安全关系:


1.线程安全是在多个线程情况下引发的,可重入函数可以在只有一个线程情况下来说;

2.可重入函数一定为线程安全的,但线程安全函数不一定为可重入函数,例如:

(1).若一个函数使用了全局和静态变量,其不是线程安全和可重入函数;

(2).若此函数使用了全局和静态变量,但加上了互斥锁等,则其为线程安全的,其保证不同线程之间互斥的访问共享数据,但没有限制同一个线程,所以其不是可重入的;

(3).若此函数只使用了其局部变量和参数,则其为线程安全与可重入的。

3.可重入函数比不可重入线程安全函数效率高一些;

4.线程安全函数能够使不同线程访问同一块地址空间,可重入函数要求不同的执行流对数据的操作互不影响使结果是相同的。


总结:当一个函数被多个线程调用时一般不会使用任何共享数据,这个函数就是可重入的,线程安全的根源在于共享数据,所以不共享任何数据的可重入函数必定为线程安全的,但线程安全可以通过同步与互斥机制来保证共享数据的使用,所以线程安全不一定为可重入的。

常见的信号处理函数是不能使用不可重入函数的。




发布了85 篇原创文章 · 获赞 56 · 访问量 9万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章