发信人: tcpip (俺的昵称改了), 信区: cnunix
标  题: Solaris多线程编程指南5--安全和不安全的接口
发信站: 哈工大紫丁香 (Sun Sep 26 15:15:47 1999), 转信

寄信人: NTMD.bbs@bbs.net.tsinghua.edu.cn 
发信站: 华南理工大学 BBS木棉站
日  期: Wed Aug  5 18:33:50 1998

发信人: Mccartney (coolcat), 信区: Unix
标  题: Solaris多线程编程指南5--安全和不安全的接口
发信站: 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的,则只有在一个线程的调用时才是安全的。

--
※ 修改:.trueip 于 Sep 26 15:19:34 修改本文.[FROM: dns.mtlab.hit.ed]
--
※ 转寄:.华南网木棉站 bbs.gznet.edu.cn.[FROM: dns.mtlab.hit.ed]

--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: trueip.bbs@melon.gzn]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.892毫秒