递归函数是否可重入

时间:2010-01-31 11:32:00

标签: recursion reentrancy

我已经看到很多递归函数(主要用于计算一些数学运算,例如阶乘,数字中的数字之和等等),其中涉及使用静态变量来保存每个递归调用的结果/操作,并将其用于后续调用。

这样做会使递归函数成为非租用函数而非线程安全。

是否存在其他不需要静态变量的递归函数用例?

7 个答案:

答案 0 :(得分:10)

这两个是不同的概念。一个并不意味着另一个,反之亦然。

例如,这是一个递归函数(假设语言)吗?

global sum = 0

proc accumulate(treeNode)
    sum += treeNode.Value
    if treeNode.Left then accumulate(treeNode.Left)
    if treeNode.Right then accumulate(treeNode.Right)
end

显然它是一个递归函数,但由于使用了全局变量,它不是可重入的。在这里,“全球”,至少我的意思是“不是函数的本地”。

然而,这是一个不好的例子,因为很容易让它完全不依赖于全局变量,只需返回总和:

func accumulate(treeNode)
    sum = treeNode.Value
    if treeNode.Left then sum += accumulate(treeNode.Left)
    if treeNode.Right then sum += accumulate(treeNode.Right)
    return sum
end

递归函数的概念中没有固有的东西可以使它成为非线程安全的或可重入的,或者相反,它完全取决于你在函数中实际编写的内容。

答案 1 :(得分:5)

  

是否存在其他不需要静态变量的递归函数用例。?

当然。实际上,递归函数中的静态变量应该是异常,而不是规则:

  

我已经看到很多递归函数(主要用于计算一些数学运算,例如阶乘,数字中的数字之和等等),其中涉及使用静态变量来保存每个递归调用的结果/操作,并将其用于后续调用。

这些都是非常坦率的糟糕实施。这里绝对不需要静态变量。他们可能充当蓄电池;这可以通过将累加器作为额外参数传递来更好地完成。

答案 2 :(得分:1)

状态通过引用或更高数据结构作为参数传递的递归函数是可重入的。

答案 3 :(得分:1)

我认为你看到的例子有缺陷。编写递归函数的标准方法使用或需要一个静态变量来存储结果;相反,你应该使用参数和/或返回值。使用静力学确实会使它们成为非租赁者,但它们不应该以这种方式编码。

使用返回值(JavaScript)的示例:

function deepCollectChildText(node) {
    var text, child;

    text = "";
    for (child = node.firstChild; child; child = child.nextSibling) {
        switch (child.nodeType) {
            case 1: // element node, may contain child nodes
                text += deepCollectChildText(child);
                break;
            case 3: // text node
                text += child.value;
                break;
        }
    }
    return text;
}

不需要静电。它本来可以用一个编码,因此不是可重入的,但它没有原因

答案 4 :(得分:0)

递归函数是线程安全的,与普通函数的程度相同,在所有语言体系结构中我都知道支持递归。每个脚步都有自己的堆栈,递归函数用于存储变量和返回地址的堆栈。

答案 5 :(得分:0)

恕我直言,如果在函数中使用静态或全局变量,它可能不是线程安全的。否则它是线程安全的。

答案 6 :(得分:0)

回顾过去的做法,我从未考虑或实践过使用静态变量进行递归函数。除常数外。

  • 可重入函数不会修改静态变量或共享资源,也不会读取静态非常量或可修改的共享资源。
  • 因此,Re-entrant =>线程安全,但反之亦然。
  • 修改静态变量的递归函数是不可重入的。

因此, 可重入的递归函数是线程安全的。 虽然非重入递归函数不是线程安全的,除非共享/静态资源的访问受到同步边界的有效约束。

然后以下问题需要回答。 如果某个函数修改了数据库记录,那么它是否会再次重入?

我在想,只要外部资源按照实例进行实例化,该功能就是可重入的。例如,具有唯一标识运行键的数据库记录。每次引用都会生成一个带有新运行密钥的新记录。

然而,这实际上就像制作一个静态变量线程安全吗?它认为它更像是一个线程安全的静态哈希表,它为每个引入生成一个唯一的键值对,因此不会在进入者之间共享关键的值对。

因此,当数据库记录或静态资源为每次访问分配其资源的唯一实例时,一个函数实际上是可重入的,但我认为由于它依赖于线程安全保护外部共享资源,学者们可能会说它是线程安全但不可重入。

对于这样的论点,我会乞求不同。例如,对于假设的编程语言,其规范并不限制其任何实现使用共享数据库或全局哈希来存储变量。因此程序员不知道在语言实现下使用的线程安全管理资源。所以程序员出去写了一个“重入”功能,或者他/她认为。那么这会使他/她的“重入函数”不可重入吗?

因此,我的结论是,只要静态/共享资源为每次进行分配一个唯一的实例,一个函数就是可重入的。

由于我缺乏更好的词汇知识,因此难以创造出引人入胜/重新引入的术语。