一、线程安全

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

       1.线程安全函数:c语言中局部变量是在栈中分配的,任何未使用静态数据或其他共享资源的函数都是线程安全的。

          (1)对于同一进程的不同线程来说,每个线程的局部变量都是私有的,而全局变量,局部静态变量,分配于堆的变量都是共享的,即是非线程安全的。

          (2)在对这些共享变量进行访问时,如果要保证线程安全,则必须通过加锁的方式。

       2.线程安全的:

                 如果一个函数在同一时刻可以被多个线程安全的调用,则称该函数是线程安全的。

                 线程安全函数解决多个线程调用函数时访问共享资源的冲突问题。

       3.线程不安全的后果:

                 共享变量的值由于不同线程的访问,可能发生不可预料的变化,进而导致程序的错误,甚至崩溃。

二、可重入函数

       当捕捉到信号时,不论进程的主控制流程当前执行到哪,都会先跳到信号处理函数中执行,从信号处理函数返回后再继续执行主控制流程。信号处理函数是一个单独的控制流程,因为它和主控制流程是异步的,二者不存在调用和被调用的关系,并且使用不同的堆栈空间。引入信号处理函数使得进程有多个控制流程,如果这些控制流程访问相同的全局资源,就有可能出现冲突。

       可重入函数主要用于多任务环境中,一个可重入函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,会出现问题,这类函数是不能运行在多任务环境下的。

       可重入函数也可以这样理解,重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外,不依赖于任何环境,这样的函数就是可重入,可以允许有该函数的多个副本在运行,由于他们使用的是分离的栈,所以不会相互干扰。如果确实需要访问全局变量,一定要注意实施互斥手段。

三、可重入函数编写规范:

       (1)不在函数内部使用静态或全局数据

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

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

       (4)如果必须访问全局变量,利用互斥机制来保护全局变量。

       (5)不调用不可重入函数。

四、线程安全与可重入函数的区别与联系

       可重入与线程安全并不等同。一般说来,可重入的函数一定是线程安全的,但反过来不一定成立。

       如果一个函数用到了全局或静态变量,那么它不是线程安全的。如果我们对它加以改进,在访问全局或静态变量时使用互斥量或信号量等方式加锁,则可以使它变成线程安全的,但此时它仍然是不可重入的,因为通常加锁方式是针对不同线程的访问,而针对同一线程则可能出现问题。如果将函数中的全局或静态变量去掉,改成函数参数等其他形式,则有可能使函变成既线程安全又可重入。

       可重入函数是线程安全安全函数的一种,其特点在于他们被多个线程调用时,不会引用任何共享数据,也就是不引用静态或全局变量。可重入函数通常要比不可重入的线程安全函数效率高一些。