Linux函数高级特性

最近在看《Linux/Unix系统编程手册》一书,这里对书中提到的函数类型进行总结。

可重入

POSIX标准中的解释如下:

Reentrant Function:
A function whose effect, when called by two or more threads,is guaranteed to be as if the threads each executed thefunction one after another in an undefined order, even ifthe actual execution is interleaved.

可重入函数跟信号相关,一种更容易理解的解释为:

程序执行到某个函数foo()时,收到信号,于是暂停目前正在执行的函数,转到信号处理函数,而这个信号处理函数的执行过程中,又恰恰也会进入到刚刚执行的函数foo(),便发生了所谓的重入。此时如果foo()能够正确的运行,而且处理完成后,之前暂停的foo()也能够正确运行,则说明它是可重入的。

可重入函数需要满足如下几个条件:

  • 不在函数内部使用静态或全局数据
  • 不返回静态或全局数据,所有数据均有函数调用者提供
  • 使用本地数据或通过复制全局数据来保护全局数据
  • 不调用不可重入函数

标准的异步安全信号函数

异步信号安全的函数指当从信号处理函数调用时,可保证实现是安全的。如果某一个函数是可重入的,或者信号处理函数无法将其中断时,称该函数是异步信号安全的。

我的理解是可重入函数和标准的异步安全信号函数基本等同,只是描述层面不同。

线程安全

若函数可同时供多个线程安全的调用,则该函数为线程安全的函数。比较容易理解。

线程安全与可重入之间的关系

可重入函数一定为线程安全的函数。线程安全函数不一定是可重入函数。

不可重入函数,函数调用结果不具有可再现性,可通过互斥锁等机制供多个线程安全的调用,这样该不可重入函数即为线程安全的函数。

malloc函数内部维护了全局数据结构,因此为不可重入的,但是内部通过递归互斥量来确保为线程安全的函数。并且该互斥量必须是可递归的,否则当malloc函数重入的情况下,会造成死锁。在glibc中,malloc有线程安全和非线程安全两个版本,两个区别在于内部是否使用递归锁,当编译程序时使用了_pthreads选项时使用线程安全版本,否则使用非线程安全版本。

自动重启

Linux中的某些系统调用在阻塞的过程中,如果接受到信号并转去处理信号处理函数,当从信号处理函数返回时这些阻塞的系统调用默认会返回EINTR。为了避免信号处理函数对阻塞中的系统调用的打断,可以通过设置SA_RESTART标志的sigaction()来建立信号处理函数,从而令内核代表进程自动重启系统调用,而无需处理系统调用返回的EINTR错误。

并非所有的系统调用都支持自动重启,具体可参考《Linux/Unix系统编程手册(上册)》的21.5节。

参考资料

《Linux/Unix系统编程手册(上册)》

对可重性和线程安全的小结