标 题: Solaris2.4 多线程编程指南5--安全和不安全的接口函?

来源:互联网 发布:淘宝just hype是正品吗 编辑:程序博客网 时间:2024/05/17 06:24

 

发信人: Mccartney (coolcat), 信区: Unix 

发信站: BBS 水木清华站 (Sun May 17 16:32:40 1998) 
 
5. 安全和不安全的接口 
 
本章定义了函数和库的多线程安全等级。 
        线程安全 
        多线程接口安全等级 
        异步安全函数 
        库的多线程安全等级 
 
5.1线程安全 
 
    线程安全是为了避免数据竞争--数据设置的正确性依赖于多个线程修改数据 
的顺序。 
    如果不需要共享,则给每个线程分配一个私有的数据拷贝。如果数据必须共 
享,一定要用同步机制来保证操作的唯一性。 
    如果一个线程在几个线程同时执行时在逻辑上是正确的,则称它为线程安全 
的。在一个实际的水平上,把安全等级划分为3层比较方便。 
        · 不安全 
        · 线程安全--非并行 
        · 线程安全--多线程安全 
    一个不安全的过程可以用在操作前加互斥锁,操作后解互斥锁的办法来使操 
作序列化(即消除并发)。示例5-1首先显示了一个简化的fputs()的非线程安全 
实现。 
    接下来是用单互斥锁保护使操作序列化的版本。实际上,使用了比需要的更 
强的同步。如果两个线程调用fputs()来打印到不同的文件时,其中一个用不着 
等待另一个--它们可以同时操作。 
    最后一个版本是多线程安全版。它给每个文件加一个锁,允许两个线程同时 
指向不同的文件。所以,MT-SAFE(即多线程安全)的函数是线程安全的,并不会使 
运行性能变坏。 
 
Code Example 5-1 线程安全的程度 
/*not thread-safe */ 
fputs(const char *s, FILE *stream){ 
                char *p; 
                for(p=s; *p; p++) 
                        putc((int)*p,stream); 
        } 
/*serializable*/ 
fputs(const char *s,FILE *stream){ 
                static mutex_t mut; 
                char *p; 
                mutex_lock(&m); 
                for(p=s;*p;p++) 
                        putc((int)*p,stream); 
                mutex_unlock(&m); 

/*MT-SAFE*/ 
mutex_t m[NFILE]; 
fputs(const char *s, FILE *stream){ 
                static mutex_t mut; 
                char *p; 
                mutex_lock(&m[fileno(stream)]); 
                for (p=s;*p;p++) 
                        putc((int)*p,stream); 
                mutex_unlock(&m[fileno(stream)]); 

 
5.2多线程接口安全等级 
 
    man page(3):库函数用下面的分类来描述一个接口支持多线程到什么程度 
(这些分类在Intro(3) man page中解释地更为详细)。 
        Safe 可以被多线程应用程序调用 
        Safe with exceptions 例外的部分请参见NOTES部分 
        Unsafe 这个接口只有在应用程序保证一个时刻只有一个线程执行时才 
                能安全调用 
        MT-Safe 完全为多线程设计,不但安全,还支持一些并发性 
        MT-Safe with exceptions 例外的部分请参见NOTES部分 
        Async-Safe 可以被一个信号控制器安全调用。一个线程在执行 
Async-Safe函数时被信号中断将不会产生死锁。 
    有关safe接口请看附录B的表"MT Safety Levels:Library Interfaces.", 
它来自man pages(3)。如果一个第三部分的接口不在表内,它就有可能是不 
安全的(不包括源兼容库Source Compatibility Library)。检查man page后才 
能确定。 
    在"man pages(2):系统调用"中描述的所有函数,除了vfork(2)外都是 
MT-Safe的。 
    一些函数有意地不作成安全,因为如下原因。 
    对于单线程的应用程序,MT-Safe回在一定程度上降低性能。 
    函数本身有一个不安全接口。例如,一个函数会返回一个指向堆栈缓冲区 
的指针。你可以用这些函数"再进入"的对等函数???(原文为 
reentrant counterparts)。再进入函数的名字是原函数加"_r"后缀。 
------------------------------------- 
注意--除非通过查询手册页(man pages),否则无法确定一个不以"_r"结尾的 
函数是否MT-safe。非MT-safe的函数一定要有同步机制的保护,或者被限制在 
初始线程里。 
------------------------------------ 
 
*非安全接口的替代(重入 Reentrant)函数 
 
    对于大多数非安全接口的函数,都存在一个MT-safe的版本。新的MT-safe函 
数一般是旧的非安全函数加上"_r"后缀。Solaris系统提供以下的"_r"函数。 
 
Table 5-1 替代函数 
asctime_r(3C)           ctermid_r(3S)           ctime_r(3C) 
fgetgrent_r(3C)         fgetpwent_r(3C)         fgetspent_r(3C) 
Gamma_r(3M)             getgrgid_r(3C)          getgrnam_r(3C) 
getlogin_r(3C)          getpwnam_r(3C)          getpwuid_r(3C) 
getgrent_r(3C)          gethostbyaddr_r(3N)     gethostbyname_r(3N) 
gethostent_r(3N)        getnetbyaddr_r(3N)      getnetbyname_r(3N) 
getnetent_r(3N)         Getprotobyname_r(3N)    getprotobynumber_r(3N) 
getprotoent_r(3N)       getpwent_r(3C)          getrpcbyname_r(3N) 
getrpcbynumber_r(3N)    getrpcent_r(3N)         getservbyname_r(3N) 
getservbyport_r(3N)     getservent_r(3N)        getspent_r(3C) 
getspnam_r(3C)          gmtime_r(3C)            lgamma_r(3M) 
localtime_(3C)r         nis_sperror_r(3N)       rand_r(3C) 
readdir_r(3C)           strtok_r(3C)            tmpnam_r(3C) 
ttyname_r(3C)            
 
5.3异步安全函数 
 
    可以被信号控制器安全调用的函数被称为Async-Safe的。POSIX标准定义并 
详列了异步安全函数(IEEE Std 1003.1-1990.3.3.1.3(3)(f), page 55)。除 
了POSIX异步安全函数外,下列三个函数也是异步安全的。 
        · sema_post(3T) 
        · thr_sigsetmask(3T) 
        · thr_kill(3T) 
 
5.4库的多线程安全等级 
 
    所有可能被多线程程序的线程调用的函数都应当是MT-Safe的。 
    这意味着过程可以同时正确地执行两个操作。所以,每一个被多线程程序 
使用的接口都应是MT-Safe。 
    并不是所有的库都是MT-Safe的。通常被使用的MT-Safe的库详列于表5-2中。 
其他的库也将最终被改写成MT-Safe的。 
        表5-2 一些MT-Safe库 
------------------------------------ 
库                                      说明 
------------------------------------ 
lib/libc                getXXbyYY接口(例如gethostbyname(3N))是MT-Safe的 
lib/libdl_stubs         (支持static switch compiling) 
lib/libintl 
lib/libm                仅当为共享库编译时是MT-Safe的,但与文档库连接时 
                        不是MT-Safe的 
lib/libmalloc 
lib/libmapmalloc 
lib/libnsl              包括TLI接口,XDR,RPC客户方和服务方,netdir和 
                        netselect。 GetXXbyYY是不安全的,但有线程安全版本 
                        GetXXbyYY_r 
lib/libresolv           支持因线程而异的错误码 
lib/libsocket 
lib/libw 
lib/nametoaddr 
lib/nametoaddr 
lib/nsswitch 
libX11 
libC                    (不是Solaris系统的部分;可以分开购买) 
------------------------------------ 
         
*不安全库 
 
    如果库中的函数不是MT-Safe的,则只有在一个线程的调用时才是安全的。 
 
-- 
※ 来源:·BBS 水木清华站 bbs.net.tsinghua.edu.cn·[FROM: sys11.cic.tsing] 
原创粉丝点击