文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>函数的线程安全与可重入

函数的线程安全与可重入

时间:2010-08-30  来源:computerhenu

函数的线程安全与可重入
刘爱贵 / 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);

 

          优点:简单易行;

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

(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》

相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载