"线程安全" 和 "可重入" 是一个概念吗?(更正帖子)

see22 2007-05-30 10:33:13
对不起,刚才发错了一个帖子,将“线程安全”写成“信号安全”了,
现在更正:

"线程安全" 和 "可重入" 是一个概念吗? 如果不是,区别在哪里?
...全文
1396 点赞 收藏 20
写回复
20 条回复
libin1201119 2011年09月07日
上面的例子不是死锁了吗,怎么还叫线程安全,求解释?
回复 点赞
zhugcx 2008年09月05日
说一个不可重入,但是线程安全的例子,帮助大家理解

funca()
{
lock(a);

......//interrupt by signal and call funca(), so dead lock

unlock(a);

}

int main()
{

signal(sig, funca);
funca();
}
回复 点赞
kakaying 2007年05月31日
学习
回复 点赞
_17708668 2007年05月31日
Chiyer(星羽) 兄给出了全局变量的线程安全处理示例:这种情况说明的是多个线程实例并发操作同一存储区域的数据的问题,就应用角度来说,本身就是不可重入的。

可重入的定义请翻阅相关课本。
微软早期的OS中的多线程是不可重入的,比如下面这个线程函数并发 3 次
void fun(void*p)
{
int i = 0;
++i;
}

最后得到的结果可能是 1,2,3 中任何结果。可能当时微软的多线程函数中的局部变量不是采用的堆栈,而是采用的共享存储。当时要做到线程函数中的局部变量相互独立(即保证线程安全,也可以说保证线程函数可重入----但可重入表现在计算科学各方面,不只是线程),Borland 提供了 C++ 多线程库。
回复 点赞
feimingbiao 2007年05月31日
这两个不是一个意思。但有时候有重叠。在多线程情况下,县城安全是可重入的必要条件。但是线程安全不一定能保证可重入。

比如单线程程序的函数,当然不存在线程安全问题,但不一定就是可重入的。比较经典的例子是最早DOS的TSR程序,由于用了同一堆栈指针,函数重入的时候会把栈写坏。还有比如Fortran一类的不支持递归的语言,由于变量是静态地址,无法可重入。

总之对于可重入函数,里面不能有大家同时可以用的公共资源。比如下面程序:

int 阶乘(int n)
{
static int i = 1;
if (n)
i = i * 阶乘(n-1);
else
i = 0;
return i;
}

即使单线程也会出问题。

回复 点赞
ming4098 2007年05月31日
学习
回复 点赞
星羽 2007年05月30日
帮 fengdream(Be an early vegetable bird~~~) ( )

这个这个文章贴出来方便看



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

(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是线程安全函数,而不是可重入函数。

回复 点赞
星羽 2007年05月30日
补考过了,还拿优 = =!
回复 点赞
星羽 2007年05月30日
怪不得,我想了半天都不知道 信号安全 跟 可重入 有什么关系 = =!


哈哈,信号安全 大学一门课,我挂了 = =!
回复 点赞
jixingzhong 2007年05月30日
http://www.ibm.com/developerworks/cn/linux/l-reent.html

【确保可重入性的经验】 部分的内容不错,
可以一看。
一些经验之谈,
可以提供有些帮助 ...
回复 点赞
jixingzhong 2007年05月30日
可以认为 可重入 是保证 线程安全 的一种方式 ...
回复 点赞
jixingzhong 2007年05月30日
基本上可以认为,如果代码是可重入的(reentrant),或者通过某种形式的互斥而实现对并发访问的保护,则代码是线程安全的。
回复 点赞
Oversense 2007年05月30日
线程安全 和 可重入 其实是2个东西,

不过一般情况下可以认为 可重入函数都是 线程安全的

也有其他 情况,这个要看定义了,比如
void foo(int *i)
{
int b = *i;
b++;
*i = b;
};
这个函数不是线程安全的,但是可重入



如果一个函数使用线程本地存储,互斥体等,也可以实现线程安全,但是可以不是 可重入的
回复 点赞
fengdream 2007年05月30日
可重入函数,是线程安全函数的一种。特点:当它们被多个线程调用时,不会引用任何共享数据,也就是不引用静态或全局变量。

请参考下面这篇文章:
http://blog.chinaunix.net/u/15929/showart.php?id=116221
回复 点赞
netxuning 2007年05月30日
学习
回复 点赞
goodluckyxl 2007年05月30日
我觉得 可重入是针对多线程中调用同一函数处理的防止异步共享导致数据不安全
它是线程安全一个可靠保证
它和线程安全应该属于一种必要关系
也就是保证纤尘安全必须保证多线程的调用函数均为可重入
而仅仅满足可重入不能满足线程安全
线程安全建立在很多安全基础之上, 需要使用信号,原子操作防止发生数据不一致导致不安全
回复 点赞
dai_weitao 2007年05月30日
我认为线程安全是由可重入和互斥两部分组成。
回复 点赞
VCLIFE 2007年05月30日
study
回复 点赞
asert 2007年05月30日
可重入函数,是线程安全函数的一种
-------------------------------
那还有哪几种,说来听听
回复 点赞
asert 2007年05月30日
mark
回复 点赞
发动态
发帖子
C语言
创建于2007-09-28

3.2w+

社区成员

24.0w+

社区内容

C语言相关问题讨论
社区公告
暂无公告