Linux/Unix编程中的线程安全问题
2013-04-19 22:55
323 查看
线程主要由控制流程和资源使用两部分构成,因此一个不得不面对的问题就是对共享资源的访问。为了确保资源得到正确的使用,开发人员在设计编写程序时需要考虑避免竞争条件和死锁,需要更多地考虑使用线程互斥变量。
判断一个函数是否线程安全不是一件很容易的事情。但是读者可以通过下面这几条确定一个函数是线程不安全的。
a, 函数中访问全局变量和堆。
b, 函数中分配,重新分配释放全局资源。
c, 函数中通过句柄和指针的不直接访问。
d, 函数中使用了其他线程不安全的函数或者变量。因此在编写线程安全函数时,要注意两点:
1, 减少对临界资源的依赖,尽量避免访问全局变量,静态变量或其它共享资源,如果必须要使用共享资源,所有使用到的地方必须要进行互斥锁 (Mutex) 保护;
2, 线程安全的函数所调用到的函数也应该是线程安全的,如果所调用的函数不是线程安全的,那么这些函数也必须被互斥锁 (Mutex) 保护;
除了线程安全还有一个很重要的概念就是 可重入(Re-entrant),所谓可重入,即:当一个函数在被一个线程调用时,可以允许被其他线程再调用。显而易见,如果一个函数是可重入的,那么它肯定是线程安全的。但反之未然,一个函数是线程安全的,却未必是可重入的。程序开发人员应该尽量编写可重入的函数。
一个函数想要成为可重入的函数,必须满足下列要求:
a) 不能使用静态或者全局的非常量数据
b) 不能够返回地址给静态或者全局的非常量数据
c) 函数使用的数据由调用者提供
d) 不能够依赖于单一资源的锁
e) 不能够调用非可重入的函数
因为多线程技术和线程安全概念出现得相对较晚,所以 POSIX规范中收纳的一些函数并不符合线程安全要求。
下表是 UNIX环境高级编程列出 POSIX.1规范中的非线程安全的函数:
目前大部分上述函数目前已经有了对应的线程安全版本的实现,例如:针对 getpwnam的 getpwnam_r(),( 这里的 _r表示可重入 (reentrant),如前所述,可重入的函数都是线程安全的)。在多线程软件开发中,如果需要使用到上所述函数,应优先使用它们对应的线程安全版本。而对于某些没有线程安全版本的函数,开发人员可按自己需要编写线程安全版本的实现。
判断一个函数是否线程安全不是一件很容易的事情。但是读者可以通过下面这几条确定一个函数是线程不安全的。
a, 函数中访问全局变量和堆。
b, 函数中分配,重新分配释放全局资源。
c, 函数中通过句柄和指针的不直接访问。
d, 函数中使用了其他线程不安全的函数或者变量。因此在编写线程安全函数时,要注意两点:
1, 减少对临界资源的依赖,尽量避免访问全局变量,静态变量或其它共享资源,如果必须要使用共享资源,所有使用到的地方必须要进行互斥锁 (Mutex) 保护;
2, 线程安全的函数所调用到的函数也应该是线程安全的,如果所调用的函数不是线程安全的,那么这些函数也必须被互斥锁 (Mutex) 保护;
除了线程安全还有一个很重要的概念就是 可重入(Re-entrant),所谓可重入,即:当一个函数在被一个线程调用时,可以允许被其他线程再调用。显而易见,如果一个函数是可重入的,那么它肯定是线程安全的。但反之未然,一个函数是线程安全的,却未必是可重入的。程序开发人员应该尽量编写可重入的函数。
一个函数想要成为可重入的函数,必须满足下列要求:
a) 不能使用静态或者全局的非常量数据
b) 不能够返回地址给静态或者全局的非常量数据
c) 函数使用的数据由调用者提供
d) 不能够依赖于单一资源的锁
e) 不能够调用非可重入的函数
因为多线程技术和线程安全概念出现得相对较晚,所以 POSIX规范中收纳的一些函数并不符合线程安全要求。
下表是 UNIX环境高级编程列出 POSIX.1规范中的非线程安全的函数:
asctime | ecvt | gethostent | getutxline | putc_unlocked |
---|---|---|---|---|
basename | encrypt | getlogin | gmtime | putchar_unlocked |
catgets | endgrent | getnetbyaddr | hcreate | putenv |
crypt | endpwent | getnetbyname | hdestroy | pututxline |
ctime | endutxent | getopt | hsearch | rand |
dbm_clearerr | fcvt | getprotobyname | inet_ntoa | readdir |
dbm_close | ftw | getprotobynumber | L64a | setenv |
dbm_delete | getcvt | getprotobynumber | lgamma | setgrent |
dbm_error | getc_unlocked | getprotoent | lgammaf | setkey |
dbm_fetch | getchar_unlocked | getpwent | lgammal | setpwent |
dbm_firstkey | getdate | getpwnam | localeconv | setutxent |
dbm_nextkey | getenv | getpwuid | lrand48 | strerror |
dbm_open | getgrent | getservbyname | mrand48 | strtok |
dbm_store | getgrgid | getservbyport | nftw | ttyname |
dirname | getgrnam | getservent | nl_langinfo | unsetenv |
dlerror | gethostbyaddr | getutxent | ptsname | wcstombs |
drand48 | gethostbyname | getutxid | ptsname | ectomb |
相关文章推荐
- Linux/Unix 编程中 POSIX 函数的线程安全问题
- Linux/Unix 编程中 POSIX 函数的线程安全问题
- Linux/Unix编程中的线程安全问题
- Linux/Unix编程中的线程安全问题
- Linux/Unix 编程中 POSIX 函数的线程安全问题
- Linux/Unix 编程中 POSIX 函数的线程安全问题
- Linux/Unix 编程中 POSIX 函数的线程安全问题
- UNIX 编程中错误输出的线程安全问题
- UNIX 编程中错误输出的线程安全问题(转载)
- UNIX 编程中错误输出的线程安全问题
- UNIX 编程中错误输出的线程安全问题
- Unix高级编程:线程基础、线程的创建、退出、分离、汇合、同步问题
- Unix(Linux)C编程问题精粹
- java线程编程安全问题
- Linux 多线程编程----线程见同步问题
- linux网络编程之posix 线程(三):posix 匿名信号量与互斥锁 示例生产者--消费者问题
- Unix环境高级编程第三版中实例代码如何在自己的linux上运行的问题
- UNIX环境高级编程学习之第十一章线程-用互斥锁传送安全线程参数
- unix/linux编程的一些问题.
- Linux History安全问题【保存记录防止删除】+完善Linux/UNIX审计 将每个shell命令记入日志