C 线程安全与可重入者
最近,我问了一个问题,题目是,在里面我问,“malloc是重新进入的吗?” 我的印象是所有的重入者都是线程安全的C 线程安全与可重入者,c,thread-safety,reentrancy,C,Thread Safety,Reentrancy,最近,我问了一个问题,题目是,在里面我问,“malloc是重新进入的吗?” 我的印象是所有的重入者都是线程安全的 这个假设是错误的吗?重入函数不依赖于C库标题中公开的全局变量。。以C中的strtok()与strtok_r()为例 有些函数需要一个位置来存储“正在进行的工作”,可重入函数允许您在线程自身的存储中指定此指针,而不是在全局内存中。由于此存储是调用函数的专用存储,因此可以中断并重新输入(重新进入),而且在大多数情况下,不需要函数实现的互斥就可以正常工作,因此通常认为它们是线程安全的。然而
这个假设是错误的吗?重入函数不依赖于C库标题中公开的全局变量。。以C中的strtok()与strtok_r()为例 有些函数需要一个位置来存储“正在进行的工作”,可重入函数允许您在线程自身的存储中指定此指针,而不是在全局内存中。由于此存储是调用函数的专用存储,因此可以中断并重新输入(重新进入),而且在大多数情况下,不需要函数实现的互斥就可以正常工作,因此通常认为它们是线程安全的。然而,定义并不能保证这一点 然而,在POSIX系统上,errno是一个稍微不同的例子(在解释这一切是如何工作的时候,它往往是一个古怪的例子):) 简言之,可重入通常意味着线程安全(如“如果使用线程,请使用该函数的可重入版本”),但线程安全并不总是意味着可重入(或相反)。当您考虑线程安全时,并发性是您需要考虑的。如果必须提供一种锁定和互斥的方法来使用函数,那么函数本身就不是线程安全的 但是,也不是所有函数都需要检查
malloc()
不需要可重入,它不依赖于任何给定线程的入口点范围之外的任何内容(并且本身是线程安全的)
如果不使用互斥锁、futex或其他原子锁定机制,返回静态分配值的函数就不是线程安全的。然而,如果它们不被中断,就不需要是可重入的
i、 e:
因此,正如您所看到的,让多个线程在没有某种锁定的情况下使用它将是一场灾难。。但它没有再进入的目的。当某些嵌入式平台上禁止动态分配内存时,您会遇到这种情况
在纯函数式编程中,可重入通常并不意味着线程安全,它取决于传递到函数入口点的已定义或匿名函数的行为、递归等
放置“线程安全”的更好方法是对并发访问的安全性,这更好地说明了这一需要 这取决于定义。例如:
- 线程安全*函数可以从多个线程同时调用,即使调用使用共享数据,因为对共享数据的所有引用都是序列化的
- 可重入函数也可以从多个线程同时调用,但前提是每次调用都使用自己的数据
/* 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;
}
/* 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;
}
/* 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;
}
/* 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;
}
示例2:线程安全,不可重入
/* 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;
}
/* 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;
}
/* 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;
}
/* 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;
}
示例3:非线程安全、可重入
/* 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;
}
/* 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;
}
/* 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;
}
/* 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;
}
示例4:线程安全、可重入
/* 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;
}
/* 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;
}
/* 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;
}
/* 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;
}
可重入并不意味着线程安全。纯函数意味着线程安全。回答得很好。只是想澄清一下,我从您的“经常”理解为线程安全并不意味着可重入,但可重入也不意味着线程安全。你能找到一个非线程安全的可重入函数的例子吗?@Tim Post“简言之,可重入通常意味着线程安全(如“如果使用线程,请使用该函数的可重入版本”),但线程安全并不总是意味着可重入。”qt相反:“因此,线程安全函数总是可重入的,但可重入函数并不总是线程安全的。”wikipedia还有另外一个说法:“重入的定义不同于多线程环境中的线程安全定义。可重入子例程可以实现线程安全[1],但在所有情况下,仅重入可能不足以实现线程安全。相反地,线程安全代码不起作用