跳到主要内容

可重入函数

1. 基本概念

多线程编程中有一个重要的概念:一个函数如果同时被多条线程调用,他返回的结果是否都是严格一致的?如果是,那么该函数被称为“可重入”函数(reentrance funciton),否则被称为“不可重入”函数。

2. 可重入函数

POSIX.1-20001标准规定,所有的标准库函数都必须是可重入函数。

3. 不可重入函数

asctime ()encrypt ()getnetbyname ()inet_ntoa ()inet_ntoa()
basename ()endgrent ()getnetent ()164a ()setkey ()
catgets ()endpwent ()getopt ()lgamma ()setpwent ()
ctermid ()endutxent ()getprotobyname ()lgammaf ()setutxent ()
ctime()fcvt ()getprotobynumber ()lgammal ()strerror ()
dbm_clearerr ()ftw ()getprotoent ()localeconv ()strsignal ()
dbm_close ()gcvt ()getpwent ()locAltime ()strtok ()
dbm_delete ()getc_unlocked ()getpwnam ()lrand48 ()system ()
dbm_error ()getchar_unlocked ()getpwuid ()mrand48 ()tmpnam ()
dbm_fetch ()getdate ()getservbyname ()nftw ()ttyname ()
dbm_firstkey ()getenv ()getservbyport ()nl_langinfo ()unsetenv ()
dbm_nextkey ()getgrent ()getservent ()ptsname ()wcrtomb ()
dbm_open ()getgrgid ()getutxent ()putc_unlocked ()wcsrtombs ()
dbm_store ()getgrnam ()getutxid ()putchar_unlocked ()wcstombs ()
dirname ()gethostbyaddr ()getutxline ()putenv ()wctomb ()
dlerror ()gethostbyname ()gmtime ()pututxline ()
drand48 ()gethostent ()hcreate ()rand ()
ecvt ()getlogin ()hdestroy ()readdir ()
crypt ()getnetbyaddr ()hsearch ()setenv ()

在使用上述函数时要注意,多条线程同时调用这些函数有可能会产生不一致的结果,产生这样结果的原因有三:

  • 一是因为函数内部使用了共享资源,比如全局变量、环境变量。

  • 二是因为函数内部调用了其他不可重入函数。

  • 三是因为函数执行结果与某硬件设备相关。

从这点出发,如果你想要写一个线程安全的可重入函数的话,只要遵循以下原则就行了:

  • 不使用任何静态数据,只使用局部变量或者堆内存。

  • 不调用上表中的任何非线程安全的不可重入函数。

如果不能同时满足以上两个条件,可以使用信号量、互斥锁等机制来确保使用静态数据或者调用不可重入函数时的互斥效果。这是编写多线程程序必须要注意的地方。