大多数时候,再入的定义引用自维基百科:

A computer program or routine is described as reentrant if it can be safely called again before its previous invocation has been completed (i.e it can be safely executed concurrently). To be reentrant, a computer program or routine: Must hold no static (or global) non-constant data. Must not return the address to static (or global) non-constant data. Must work only on the data provided to it by the caller. Must not rely on locks to singleton resources. Must not modify its own code (unless executing in its own unique thread storage) Must not call non-reentrant computer programs or routines.

如何定义安全?

如果一个程序可以安全地并发执行,那么它是否总是意味着它是可重入的?

在检查代码的重入功能时,我应该记住的这六点之间的共同点究竟是什么?

同时,

是否所有递归函数都是可重入的? 是否所有线程安全的函数都是可重入的? 是否所有递归和线程安全的函数都是可重入的?


在写这个问题的时候,我想到了一件事: 像重入和线程安全这样的术语是绝对的吗?也就是说,它们有固定的具体定义吗?因为,如果不是,这个问题就没有多大意义。


当前回答

共同点是:

如果在中断时调用例程,行为是否定义良好?

如果你有这样一个函数:

int add( int a , int b ) {
  return a + b;
}

这样它就不依赖于任何外部状态。行为定义良好。

如果你有这样一个函数:

int add_to_global( int a ) {
  return gValue += a;
}

结果在多个线程上没有很好地定义。如果时机不对,信息可能会丢失。

可重入函数的最简单形式是只对传递的参数和常量值进行操作。其他任何东西都需要特殊处理,或者通常是不可重入的。当然参数不能引用可变全局变量。

其他回答

你的“同样”问题的答案是“不”,“不”和“不”。仅仅因为函数是递归的和/或线程安全的,并不意味着它是可重入的。

每一种类型的函数都可能在你引用的所有点上失败。(虽然我不是100%确定第五点)。

“安全”的定义完全符合常识——它意味着“正确地做自己的事情,而不干扰其他事情”。你提到的六点很清楚地表达了实现这一目标的要求。

你的三个问题的答案是3ד不”。


是否所有递归函数都是可重入的?

NO!

同时调用一个递归函数很容易把彼此搞砸,如果 例如,它们访问相同的全局/静态数据。


是否所有线程安全的函数都是可重入的?

NO!

如果一个函数在并发调用时不发生故障,那么它就是线程安全的。但这可以通过使用互斥来阻止第二次调用的执行,直到第一次调用完成,这样一次只有一个调用可以工作。可重入性意味着在不干扰其他调用的情况下并发执行。


是否所有递归和线程安全的函数都是可重入的?

NO!

见上图。

不可重入函数意味着将有一个静态上下文,由函数维护。第一次进入时,将为您创建新的上下文。下一个输入,你不需要发送更多的参数,为了方便标记分析。例如c中的strtok,如果你没有清楚上下文,可能会有一些错误。

/* strtok example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

on the contrary of non-reentrant, reentrant function means calling function in anytime will get the same result without side effect. because there is none of context. in the view of thread safe, it just means there is only one modification for public variable in current time, in current process. so you should add lock guard to ensure just one change for public field in one time. so thread safety and reentrant are two different things in different views.reentrant function safety says you should clear context before next time for context analyze. thread safety says you should keep visit public field order.

共同点是:

如果在中断时调用例程,行为是否定义良好?

如果你有这样一个函数:

int add( int a , int b ) {
  return a + b;
}

这样它就不依赖于任何外部状态。行为定义良好。

如果你有这样一个函数:

int add_to_global( int a ) {
  return gValue += a;
}

结果在多个线程上没有很好地定义。如果时机不对,信息可能会丢失。

可重入函数的最简单形式是只对传递的参数和常量值进行操作。其他任何东西都需要特殊处理,或者通常是不可重入的。当然参数不能引用可变全局变量。

所列出的要点中的“共同主线”(双关语!?)是函数不能做任何会影响对同一函数的任何递归或并发调用的行为的事情。

比如静态数据就是个问题因为它属于所有线程;如果一个调用修改了一个静态变量,那么所有线程都会使用修改后的数据,从而影响它们的行为。自修改代码(虽然很少遇到,在某些情况下被阻止)将是一个问题,因为尽管有多个线程,但只有一个代码副本;代码也是基本的静态数据。

从本质上讲,要实现可重入,每个线程必须能够使用函数,就像它是唯一的用户一样,如果一个线程可以以不确定的方式影响另一个线程的行为,则情况就不是这样了。这主要涉及到每个线程都有函数所处理的独立数据或常量数据。

综上所述,第(1)点不一定是正确的;例如,您可以合理地设计使用静态变量来保留递归计数,以防止过度递归或分析算法。

A thread-safe function need not be reentrant; it may achieve thread safety by specifically preventing reentrancy with a lock, and point (6) says that such a function is not reentrant. Regarding point (6), a function that calls a thread-safe function that locks is not safe for use in recursion (it will dead-lock), and is therefore not said to be reentrant, though it may nonetheless safe for concurrency, and would still be re-entrant in the sense that multiple threads can have their program-counters in such a function simultaneously (just not with the locked region). May be this helps to distinguish thread-safety from reentarncy (or maybe adds to your confusion!).