场景描述:
在捕捉到信号时,不论进程的主控制流程执行到哪里,在未设计信号阻塞时,都会先跳到信号处理函数中去执行,从信号处理函数返回后再继续执行主控制流程,信号处理函数是一个单独的控制流程,因为它和主控制流程是异步的,两者不存在调用与被调用的关系,并且使用不同的堆栈空间,引入了信号处理函数使得一个进程具有多个控制流程,如果这些控制流程访问相同的全局资源(全局变量,硬件资源),则可能会发生冲突(导致全局变量在信号处理函数中被错误的修改等)
什么叫做重入:
举个例子来说,在主控制流程中调用了fun()函数,但是在执行fun函数的代码段中间时,被某个信号中断,转去执行信号处理函数,在信号处理函数中又去调用fun()函数,这个叫做重入。也就是说一个函数在不同的控制流程中被同时调用,在一个控制流程中该函数尚未返回时,在另外的控制流程中该函数又被调用。
什么是可重入函数:
一个函数可以被多个任务或者是多个控制流程并发的访问,而不用担心数据错误或者是执行的结果具有可预见性。典型的情况就是函数仅使用局部变量,这个时候在不同的控制流程中调用相同的函数,会在栈空间中维护局部变量而非堆空间中,这样改变的数据也仅仅是当时正在执行的函数的数据,当函数执行完之后栈空间释放,当然不会影响到另外的控制流程中的同一个函数
什么叫做不可重入函数:
把上面的可重入函数的概念改改就行了。或者是这样理解也行:如果函数在重入条件下使用了未受保护的全局资源,则称为不可重入函数
为使我们自己写的函数成为可重入的,应该:
不在函数中使用静态变量或者是全局变量
不返回全局或者是静态数据,所有的数据都由函数的调用者提供
使用本地变量,即使使用全局变量,也使用全局变量的本地拷贝
使用全局数据时,加锁保护
不调用不可重入函数。
不可重入函数除了上诉相反的条件外,还有:
函数调用了malloc()或者是free()
函数调用了标准I/O函数(很多的标准I/O函数都以不可重入的方式使用了全局数据结构,比如隶属于进程的缓冲区)
个人认为其实可重入函数的前几条说的都是一件事,尽量不要使用堆中的数据。因为堆中的数据可以被共享。
apue中关于不可重入函数的例子举得是getpwnam()这个函数,原因在于这个函数会返回静态的数据结构。这样如果在一个控制流程进程getpwnam的调用的时候被中断执行,在另外的控制流程中调用getpwnam函数,则可能出现问题,因为静态类型的变量会在函数调用中维持其值。
注意:本人非科班出身,学习apue纯属 个人爱好,希望多加指正不足之处。