Chinaunix首页 | 论坛 | 博客
  • 博客访问: 192497
  • 博文数量: 73
  • 博客积分: 5000
  • 博客等级: 大校
  • 技术积分: 1160
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-23 15:53
文章分类

全部博文(73)

文章存档

2011年(1)

2009年(72)

我的朋友

分类: LINUX

2009-04-23 17:14:04

函数的线程安全与可重入
刘爱贵 / Aiguille.LIU

http://liuaigui.blog.sohu.com/86494742.html

线程安全的(Thread-Safe):如果一个函数在同一时刻可以被多个线程安全地调用,就称该函数是线程安全的。线程安全函数解决多个线程调用函数时访问共享资源的冲突问题。

可重入(Reentrant):函数可以由多于一个线程并发使用,而不必担心数据错误。可重入函数可以在任意时刻被中断,稍后再继续运行,不会丢失数据。可重入性解决函数运行结果的确定性和可重复性。可重入函数编写规范为:
1
、不在函数内部使用静态或全局数据
2
、不返回静态或全局数据,所有数据都由函数的调用者提供。
3
、使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据。
4
、如果必须访问全局变量,利用互斥机制来保护全局变量。
5
、不调用不可重入函数。

两者之间的关系:
1
、一个函数对于多个线程是可重入的,则这个函数是线程安全的。
2
、一个函数是线程安全的,但并不一定是可重入的。
3
、可重入性要强于线程安全性。

比如:strtok函数是既不可重入的,也不是线程安全的。加锁的strtok不是可重入的,但线程安全。而strtok_r既是可重入的,也是线程安全的。(具体可以查看man手册)


关于线程安全与可重入性

http://blog.chinaunix.net/u/15929/showart.php?id=116221

 

   一个函数被称作“线程安全”的,当且仅当它被多个线程反复调用时,它会一直产生令人期待的正确的结果。反之为“线程不安全”函数,它主要有两种类型:

1)不保护共享变量的函数,包括全局变量和本地静态变量(static)。

      我们可以使用POSIX信号量加以解决:

                                              Sem_t  mutex;

                       Sem_init(&mutex,0,1);

                       Sem_wait(&mutex);

                          ……

                          ……

                       Sem_post(&mutex);

 

          优点:简单易行;

 缺点:同步操作pv将影响程序的执行时间。

2)返回指向静态变量的指针的函数,如gethostbyname,gethostbyaddr,inet_ntoa等等。

     我一般这样使用gethodtbyname:

                                 

                 Struct hostent *hostp;

                 Hostp=gethostbyname(scorpion.cublog.cn);

                     ……

        ……

Gethostbyname将执行结果存放在自己的static struct hostent变量中,并返回一个指向这个结构的指针。如果我们从并发线程中调用这个函数,那么将发生不可预料的结果,正在被一个线程使用的结果,可能悄悄地被其它线程覆盖。

解决办法:(a)、改写库函数gethostbyname,增加一个参数,将本地结构变量传入gethostbyname,

如:

         Struct hostent host;

         Gethostbyname(&host,scorpion.cublog.cn);

     再使用host方可!

 

b)、改写库函数gethostbyname,不是返回指针,而是直接返回struct hostent.

     缺点:struct hostent结构较大,影响函数的效率。

 

  以上两种办法(a)、(b),要求修改库函数,基本上不可行!

 

c、使用lock –and-copy技术,即定义自己的封装函数,通过调用它来取代直接使用gethostbyname.

        

struct hostent *gethostbyname_my(char *hostname)

{

       struct hostent *shar,*unshar;

       unshar=malloc(sizeof(struct hostent))

       sem_wait(&mutex);

       shar=gethosybyname(hostname);

       *unshar=*shar;

       srm_post(&mutex);

       return unshar;

}

 

    现在大多数unix\linux操作系统,提供了线程不安全函数的可重入版本,如:gethostbyname_r。但是不同的系统可能接口不一样,所以建议不使用它们!还是使用我们自己的封装函数。

 

   可重入函数,是线程安全函数的一种。特点:当它们被多个线程调用时,不会引用任何共享数据,也就是不引用静态或全局变量。如,gethostbyname_my是线程安全函数,而不是可重入函数。

 

参考书目:《深入理解计算机系统》、《UNIX网络编程 1

阅读(661) | 评论(0) | 转发(0) |
0

上一篇:linux 调试工具总结

下一篇:静态变量浅析

给主人留下些什么吧!~~