Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 线程安全与可重入者_C_Thread Safety_Reentrancy - Fatal编程技术网

C 线程安全与可重入者

C 线程安全与可重入者,c,thread-safety,reentrancy,C,Thread Safety,Reentrancy,最近,我问了一个问题,题目是,在里面我问,“malloc是重新进入的吗?” 我的印象是所有的重入者都是线程安全的 这个假设是错误的吗?重入函数不依赖于C库标题中公开的全局变量。。以C中的strtok()与strtok_r()为例 有些函数需要一个位置来存储“正在进行的工作”,可重入函数允许您在线程自身的存储中指定此指针,而不是在全局内存中。由于此存储是调用函数的专用存储,因此可以中断并重新输入(重新进入),而且在大多数情况下,不需要函数实现的互斥就可以正常工作,因此通常认为它们是线程安全的。然而

最近,我问了一个问题,题目是,在里面我问,“malloc是重新进入的吗?”

我的印象是所有的重入者都是线程安全的


这个假设是错误的吗?

重入函数不依赖于C库标题中公开的全局变量。。以C中的strtok()与strtok_r()为例

有些函数需要一个位置来存储“正在进行的工作”,可重入函数允许您在线程自身的存储中指定此指针,而不是在全局内存中。由于此存储是调用函数的专用存储,因此可以中断并重新输入(重新进入),而且在大多数情况下,不需要函数实现的互斥就可以正常工作,因此通常认为它们是线程安全的。然而,定义并不能保证这一点

然而,在POSIX系统上,errno是一个稍微不同的例子(在解释这一切是如何工作的时候,它往往是一个古怪的例子):)

简言之,可重入通常意味着线程安全(如“如果使用线程,请使用该函数的可重入版本”),但线程安全并不总是意味着可重入(或相反)。当您考虑线程安全时,并发性是您需要考虑的。如果必须提供一种锁定和互斥的方法来使用函数,那么函数本身就不是线程安全的

但是,也不是所有函数都需要检查
malloc()
不需要可重入,它不依赖于任何给定线程的入口点范围之外的任何内容(并且本身是线程安全的)

如果不使用互斥锁、futex或其他原子锁定机制,返回静态分配值的函数就不是线程安全的。然而,如果它们不被中断,就不需要是可重入的

i、 e:

因此,正如您所看到的,让多个线程在没有某种锁定的情况下使用它将是一场灾难。。但它没有再进入的目的。当某些嵌入式平台上禁止动态分配内存时,您会遇到这种情况

在纯函数式编程中,可重入通常并不意味着线程安全,它取决于传递到函数入口点的已定义或匿名函数的行为、递归等


放置“线程安全”的更好方法是对并发访问的安全性,这更好地说明了这一需要

这取决于定义。例如:

  • 线程安全*函数可以从多个线程同时调用,即使调用使用共享数据,因为对共享数据的所有引用都是序列化的

  • 可重入函数也可以从多个线程同时调用,但前提是每次调用都使用自己的数据

因此,线程安全函数总是可重入的,但可重入函数并不总是线程安全的

通过扩展,如果一个类的成员函数可以从多个线程安全地调用,则该类被称为可重入的,只要每个线程使用该类的不同实例。如果可以从多个线程安全地调用其成员函数,则该类是线程安全的,即使所有线程都使用该类的同一实例

但他们也警告说:

注意:多线程领域中的术语没有完全标准化。POSIX使用可重入和线程安全的定义,这两种定义对于其C API来说有些不同。当使用QT使用其他面向对象C++类库时,请确保理解定义。

TL;DR:函数可以是可重入的,线程安全的,两者都可以,或者两者都不能

和的维基百科文章非常值得一读。以下是一些引文:

函数是线程安全的,如果:

它只处理中的共享数据结构 一种保证多个程序安全执行的方式 线程同时运行

函数是可重入的,如果:

它可以在执行过程中的任何时候中断 然后安全地再次呼叫(“重新进入”),然后 以前的调用完成了执行

作为可能的重入的例子,维基百科给出了一个被系统中断调用的函数的例子:假设当另一个中断发生时它已经在运行。但不要因为不使用系统中断编码就认为自己是安全的:如果使用回调或递归函数,单线程程序中可能会出现重入问题

避免混淆的关键是reentrant指 只有一个线程正在执行。这是一个从 不存在多任务操作系统

示例

(从维基百科文章中稍作修改)

示例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;
}
/* 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],但在所有情况下,仅重入可能不足以实现线程安全。相反地,线程安全代码不起作用