Chinaunix首页 | 论坛 | 博客
  • 博客访问: 988479
  • 博文数量: 200
  • 博客积分: 5011
  • 博客等级: 大校
  • 技术积分: 2479
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-27 15:07
文章分类

全部博文(200)

文章存档

2009年(12)

2008年(190)

我的朋友

分类:

2008-12-16 10:20:54

12.5 reentrancy

(一)reentrancy thread safty 以及 async-signal safety 的关系

Reentrant function并不是一个确定的概念,我们可以说这个函数是thread reentrant function,所以它是一个thread safe function.意思是说这个函数是可以被别的thread同时调用的。我们还可以说另一个函数是signal reentrant function 所以它是一个async signal safe function。意思是说这个函数可以被signal打断,然后再signal handler里面再次调用它。所以当我们说一个函数是reentrant函数的时候,要指明是针对thread,还是针对signal。如果我们不知名的话,我们的意思就是说全部都包括。即既thread reentrantssync-signal reentrant。这就是广义的reentrant function.

广义的reentrant function的定义:(摘自wiki reentrant(subroutine)

  • Must hold no static (global) non-constant data.
  • Must not return the address to static (global) non-constant data.
  • Must work only on the data provided to it by the caller.
  • Must not rely on locks to resources.
  • Must not call non-reentrant functions.

看到没,倒数第2点,不需使用锁来访问一些资源,所以一个thread safefunction就可能被排除在外了,因为thread reentrant(thread safe)函数有可能就是靠锁来实现的。所以thread reentrant(thread safe) 函数并不算严格意义的reentrant函数,因为它不能做到async-signal reentrant

所以:

1.一个reentrant函数一定是thread safe

2.一个thread safe的函数不一定是reentrant的。比如你是thread safe的,但不是async-signal safe的,看上边的死锁的例子。

 

Threadsignal的区别:

1 Thread是并行执行的, 特别是对于多cpu的环境,是真正的并行执行

2Signal handler与被signal中断的程序不是并行的,被中断的程序stop, signal handler执行完后,才继续。

由于上述特点,thread可以用锁来保证同步,可以使我们的函数thread reentrant,即threa safe. 但是,signal handler就不一定可以,特别是如果你在你的一个函数里,已经加了普通锁,signal 发生,程序被打断,handler执行,handler里面又加锁,这就会造成死锁(前提是你使用的不是recursive锁)。可见signal reentrant要比thread reentrant更严格。

举个例子:你的正在调用printf函数,她正在处理标准输出,突然收到信号,在handler里面也调用printf,那么你就可能死锁。因为printf函数为了实现thread safe, 在里面自己给FILE加锁了。在你释放之前,又调用printf去加锁当然就死锁了(前提是我们使用的不是recursive锁)。

 

(二)针对stdandard i/o library要做到thread safe的方法

FILE object中加入了一个lock,普通的standard i/o library都会首先给这个FILE object加锁,然后再去处理,这个锁是recurive锁。我们可以假设所有的standard i/o 函数都会自动加锁和释放锁,来处理FILE对象,所以我们知道standard i/o librarythread reentrant的,也就是thread safe的。

#include

 

int ftrylockfile(FILE *fp);

 

Returns: 0 if OK, nonzero if lock can't be acquired

void flockfile(FILE *fp);

 

void funlockfile(FILE *fp);

 

这就是他们使用的加锁函数,但是这个函数既然是standard i/o library内部使用的,那为什么将他们expose给用户呢?因为有时候,用户需要手动根据特殊情况修改对FILE object的加锁情况。比如,用户想手动来控制加锁以提高性能:

1.我想将若干个standard i/o library的操作序列执行完后才允许别的thread来进行操作时,就可以先手动加锁,然后调用若干standard i/o 的函数,然后再释放锁。

2.有些使用频率很高的standard i/o函数,每次调用都加锁/解锁,性能会下降。所以我们可以手动加锁,然后调用n次不自动加锁的standard i/o函数,然后再释放锁。于是就有了不自动加锁的standard i/o function版本。

比如Getch函数,本身只处理一个字符,如果每次调用都加锁再释放,而且调用频率极高,那么就会性能下降。我们可以将若干个不自动加锁的getch联合起来,一起加锁,比如加锁后,调用10getch再释放锁。

#include

 

int getchar_unlocked(void);

 

int getc_unlocked(FILE *fp);

 

Both return: the next character if OK, EOF on end of file or error

int putchar_unlocked(int c);

 

int putc_unlocked(int c, FILE *fp);

 

Both return: c if OK, EOF on error

这就使不自动加锁的getchar函数版本。

(三)一些网上的资源

1Writing signal-safe code: 通过举例的方式阐述清楚了thread safesignal safe的区别和如何写signal safe的代码的探讨

http://www.cocoadev.com/index.pl?SignalSafety

2. Use reentrant functions for safer signal handling

http://www.ibm.com/developerworks/linux/library/l-reent.html

阅读(945) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~