最近,我问了一个问题,标题为“ malloc线程安全吗?” ,然后我问:“ malloc是否可重入?”
我的印象是所有重入者都是线程安全的。
这个假设错了吗?
函数可以是可重入的,线程安全的,或者两者均可。
维基百科上有关线程安全性和可重入性的文章非常值得一读。这里有一些引用:
在以下情况下,函数是线程安全的:
它仅以确保多个线程同时安全执行的方式操作共享数据结构。
在以下情况下,函数是可重入的:
它可以在执行过程中的任何时候中断,然后在之前的调用完成执行之前安全地再次调用(“重新输入”)。
作为可能重新进入的示例,维基百科给出了一个设计为由系统中断调用的函数的示例:假设当另一个中断发生时该函数已经在运行。但是不要仅仅因为您不使用系统中断进行编码就认为您是安全的:如果使用回调或递归函数,则在单线程程序中可能会遇到重入问题。
避免混淆的关键是可重入仅指一个正在执行的线程。从不存在多任务操作系统的时代开始就是一个概念。
例子
(从维基百科的文章稍作修改)
示例1:不是线程安全的,不是可重入的
/* As this function uses a non-const global variable without
any precaution, it is neither reentrant nor thread-safe. */
int t;
void swap(int *x, int *y)
{
t = *x;
*x = *y;
*y = t;
}
示例2:线程安全,不可重入
/* We use a thread local variable: the function is now
thread-safe but still not reentrant (within the
same thread). */
__thread int t;
void swap(int *x, int *y)
{
t = *x;
*x = *y;
*y = t;
}
示例3:不是线程安全的,可重入
/* We save the global state in a local variable and we restore
it at the end of the function. The function is now reentrant
but it is not thread safe. */
int t;
void swap(int *x, int *y)
{
int s;
s = t;
t = *x;
*x = *y;
*y = t;
t = s;
}
示例4:线程安全,可重入
/* We use a local variable: the function is now
thread-safe and reentrant, we have ascended to
higher plane of existence. */
void swap(int *x, int *y)
{
int t;
t = *x;
*x = *y;
*y = t;
}
这取决于定义。例如,Qt使用以下内容:
即使调用使用共享数据,也可以从多个线程同时调用线程安全*函数,因为对共享数据的所有引用都已序列化。
一个可重入函数也可以从多个线程同时调用,但只有当每个调用使用自己的数据。
因此,线程安全函数始终是可重入的,但是重入函数并不总是线程安全的。
通过扩展,如果可以从多个线程安全地调用其成员函数,则该类称为可重入的,只要每个线程使用该类的不同实例即可。如果可以从多个线程安全地调用其成员函数,则该类是线程安全的,即使所有线程都使用该类的相同实例也是如此。
但他们也警告:
注意:多线程域中的术语尚未完全标准化。POSIX使用可重入和线程安全的定义,这些定义对其C API有所不同。当将其他面向对象的C ++类库与Qt一起使用时,请确保理解定义。
举报