线程安全和可重入函数

一、线程安全及如何避免
线程的概念:
        由我们已知的知识,main函数和信号处理函数是同一个进程地址空间中的多个控制流程,多线程也是如此,但是比信号处理函数更加灵活,信号处理函数的控制流程只是在信号递达时产生,在处理完信号之后就结束,而多线程的控制流程可以长期并存,操作系统会在个线程之间调度和切换就像在多进程之间切换和调度一样。由于同一进程的多个线程共享一个地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在个线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,线程还可以共享一下资源和环境:文件描述符表,每种信号的处理方式,当前的工作目录,用户id和组id。
       在任何一个时间点上,线程是可结合的或者是可分离的。一个可结合的线程能够被其他线程收回其资源和杀死。再被其他线程收回之前,它的存储器资源是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,他的存储器资源在它终止时有系统自动释放。
       而在默认情况下,线程被创建成可结合的,为了避免存储器泄露,每个可结合线程都应该要么被显示地回收,即调用pthread_join;要么通过调用pthread_detach函数被分离。

线程安全:一个函数被称为线程安全的,当且仅当被多个并发进程反复调用时,它会一直产生正确的结果。反之,如果一个线程是不安全的,我们称它为线程不安全的。
线程的安全问题一般都是由全局变量及静态变量引起的。其有几种不安全的类型。做好它们就能在很大程度上面避免线程的不安全。
1.提供保护变量的函数,用P,V等函数来保护共享变量,防止干扰及调用出错。
2.尽量减少跨越多个调用的状态函数。
3.尽量减少在函数内部使用静态变量和全局变量。
4.如果一定要使用全局变量,利用互斥机制来保护全局变量。


二、可重入函数

        可重入函数:一个函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入。一个函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为不可重入函数,反之,如果一个函数只访问自己的局部变量或参数,则称为可重入函数。
        如果函数符合以下条件之一则是不可重入的:
调用了malloc或free,因为malloc也是用全局链表来管理堆的。
调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。
使用静态的数据结构。

可重入函数的特点:
1、可重入函数调用多次不会出错,其不用担心数据出错。
2、其被多个线程调用时,不会引用任何共享数据。
3.可重入函数可以在任意时刻被终断,稍后再继续运行,不会丢失任何数据,可重入函数要么使用本地变量,要么在使用全局变量时保护自己的数据。

三、两者之间的联系: 1.一个函数对于多个线程是可重入的,则这个函数是线程安全的。 2.一个函数是可重入的但不一定是线程安全的。 3.线程安全是在多个线程的情况下引发的,但是可重入函数可以在只有一个线程的情况下来说。