C++ 什么是可重入函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2799023/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:06:07  来源:igfitidea点击:

What exactly is a reentrant function?

c++crecursionthread-safetyreentrancy

提问by Lazer

Mostofthetimes, the definition of reentrance is quoted from Wikipedia:

大多数时代,再进入的定义转引自维基百科

A computer program or routine is described as reentrant if it can be safelycalled again before its previous invocation has been completed (i.e it can be safely executed concurrently). To be reentrant, a computer program or routine:

  1. Must hold no static (or global) non-constant data.
  2. Must not return the address to static (or global) non-constant data.
  3. Must work only on the data provided to it by the caller.
  4. Must not rely on locks to singleton resources.
  5. Must not modify its own code (unless executing in its own unique thread storage)
  6. Must not call non-reentrant computer programs or routines.

如果一个计算机程序或例程可以在其前一次调用完成之前安全地再次调用(即它可以安全地并发执行),则它被描述为可重入的 。可重入的,计算机程序或例程:

  1. 不得包含静态(或全局)非常量数据。
  2. 不得将地址返回给静态(或全局)非常量数据。
  3. 必须只处理调用者提供给它的数据。
  4. 不能依赖对单例资源的锁。
  5. 不得修改自己的代码(除非在自己唯一的线程存储中执行)
  6. 不得调用不可重入的计算机程序或例程。

How is safelydefined?

如何定义安全

If a program can be safely executed concurrently, does it always mean that it is reentrant?

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

What exactly is the common thread between the six points mentioned that I should keep in mind while checking my code for reentrant capabilities?

在检查我的代码是否具有可重入功能时,我应该记住的六点之间的共同点到底是什么?

Also,

还,

  1. Are all recursive functions reentrant?
  2. Are all thread-safe functions reentrant?
  3. Are all recursive and thread-safe functions reentrant?
  1. 所有递归函数都是可重入的吗?
  2. 所有线程安全函数都是可重入的吗?
  3. 所有递归和线程安全函数都是可重入的吗?


While writing this question, one thing comes to mind: Are the terms like reentranceand thread safetyabsolute at all i.e. do they have fixed concrete definations? For, if they are not, this question is not very meaningful.

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

采纳答案by paercebal

1. How is safelydefined?

1.安全是如何定义的?

Semantically. In this case, this is not a hard-defined term. It just mean "You can do that, without risk".

语义上。在这种情况下,这不是一个硬定义的术语。它只是意味着“你可以做到,没有风险”。

2. If a program can be safely executed concurrently, does it always mean that it is reentrant?

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

No.

不。

For example, let's have a C++ function that takes both a lock, and a callback as a parameter:

例如,让我们有一个 C++ 函数,它将锁和回调作为参数:

#include <mutex>

typedef void (*callback)();
std::mutex m;

void foo(callback f)
{
    m.lock();
    // use the resource protected by the mutex

    if (f) {
        f();
    }

    // use the resource protected by the mutex
    m.unlock();
}

Another function could well need to lock the same mutex:

另一个函数很可能需要锁定相同的互斥锁:

void bar()
{
    foo(nullptr);
}

At first sight, everything seems ok… But wait:

乍一看,一切似乎都很好……但是等等:

int main()
{
    foo(bar);
    return 0;
}

If the lock on mutex is not recursive, then here's what will happen, in the main thread:

如果互斥锁上的锁不是递归的,那么在主线程中会发生以下情况:

  1. mainwill call foo.
  2. foowill acquire the lock.
  3. foowill call bar, which will call foo.
  4. the 2nd foowill try to acquire the lock, fail and wait for it to be released.
  5. Deadlock.
  6. Oops…
  1. main会打电话foo
  2. foo将获得锁。
  3. foo将调用bar,这将调用foo
  4. 第二个foo将尝试获取锁,失败并等待它被释放。
  5. 僵局。
  6. 糟糕…

Ok, I cheated, using the callback thing. But it's easy to imagine more complex pieces of code having a similar effect.

好吧,我欺骗了,使用回调的东西。但是很容易想象具有类似效果的更复杂的代码段。

3. What exactly is the common thread between the six points mentioned that I should keep in mind while checking my code for reentrant capabilities?

3. 在检查代码的可重入能力时,我应该牢记的六点之间的共同点究竟是什么?

You can smella problem if your function has/gives access to a modifiable persistent resource, or has/gives access to a function that smells.

如果您的函数具有/授予访问可修改持久资源的权限,或者具有/授予访问气味的函数,则您可以到问题。

(Ok, 99% of our code should smell, then… See last section to handle that…)

好吧,我们 99% 的代码都应该有味道,然后……请参阅最后一节来处理……

So, studying your code, one of those points should alert you:

因此,在研究您的代码时,其中一点应该提醒您:

  1. The function has a state (i.e. access a global variable, or even a class member variable)
  2. This function can be called by multiple threads, or could appear twice in the stack while the process is executing (i.e. the function could call itself, directly or indirectly). Function taking callbacks as parameters smella lot.
  1. 函数有状态(即访问全局变量,甚至类成员变量)
  2. 该函数可以被多个线程调用,也可以在进程执行时在堆栈中出现两次(即该函数可以直接或间接调用自身)。将回调作为参数的函数气味很大。

Note that non-reentrancy is viral : A function that could call a possible non-reentrant function cannot be considered reentrant.

请注意,不可重入是病毒式的:可以调用可能的不可重入函数的函数不能被视为可重入的。

Note, too, that C++ methods smellbecause they have access to this, so you should study the code to be sure they have no funny interaction.

还要注意,C++ 方法的气味是因为它们可以访问this,因此您应该研究代码以确保它们没有有趣的交互。

4.1. Are all recursive functions reentrant?

4.1. 所有递归函数都是可重入的吗?

No.

不。

In multithreaded cases, a recursive function accessing a shared resource could be called by multiple threads at the same moment, resulting in bad/corrupted data.

在多线程情况下,访问共享资源的递归函数可能会同时被多个线程调用,从而导致数据错误/损坏。

In singlethreaded cases, a recursive function could use a non-reentrant function (like the infamous strtok), or use global data without handling the fact the data is already in use. So your function is recursive because it calls itself directly or indirectly, but it can still be recursive-unsafe.

在单线程情况下,递归函数可以使用不可重入函数(如臭名昭著的strtok),或者使用全局数据而不处理数据已经在使用的事实。所以你的函数是递归的,因为它直接或间接地调用自己,但它仍然可以是递归不安全的

4.2. Are all thread-safe functions reentrant?

4.2. 所有线程安全函数都是可重入的吗?

In the example above, I showed how an apparently threadsafe function was not reentrant. OK, I cheated because of the callback parameter. But then, there are multiple ways to deadlock a thread by having it acquire twice a non-recursive lock.

在上面的例子中,我展示了一个明显的线程安全函数是如何不可重入的。好吧,我因为回调参数而作弊。但是,有多种方法可以通过让线程获取两次非递归锁来死锁线程。

4.3. Are all recursive and thread-safe functions reentrant?

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

I would say "yes" if by "recursive" you mean "recursive-safe".

如果“递归”是指“递归安全”,我会说“是”。

If you can guarantee that a function can be called simultaneously by multiple threads, and can call itself, directly or indirectly, without problems, then it is reentrant.

如果你能保证一个函数可以被多个线程同时调用,并且可以直接或间接调用自己,没有问题,那么它就是可重入的。

The problem is evaluating this guarantee… ^_^

问题是评估这个保证……^_^

5. Are the terms like reentrance and thread safety absolute at all, i.e. do they have fixed concrete definitions?

5. 重入和线程安全等术语是否是绝对的,即它们是否有固定的具体定义?

I believe they do, but then, evaluating a function is thread-safe or reentrant can be difficult. This is why I used the term smellabove: You can find a function is not reentrant, but it could be difficult to be sure a complex piece of code is reentrant

我相信他们确实如此,但是,评估一个函数是线程安全的还是可重入的可能很困难。这就是我使用上面气味这个术语的原因:你可以发现一个函数是不可重入的,但是很难确定一段复杂的代码是可重入的

6. An example

6. 一个例子

Let's say you have an object, with one method that needs to use a resource:

假设您有一个对象,其中一个方法需要使用资源:

struct MyStruct
{
    P * p;

    void foo()
    {
        if (this->p == nullptr)
        {
            this->p = new P();
        }

        // lots of code, some using this->p

        if (this->p != nullptr)
        {
            delete this->p;
            this->p = nullptr;
        }
    }
};

The first problem is that if somehow this function is called recursively (i.e. this function calls itself, directly or indirectly), the code will probably crash, because this->pwill be deleted at the end of the last call, and still probably be used before the end of the first call.

第一个问题是,如果以某种方式递归调用这个函数(即这个函数直接或间接调用自己),代码可能会崩溃,因为this->p会在最后一次调用结束时被删除,并且可能在结束前仍然使用第一个电话。

Thus, this code is not recursive-safe.

因此,此代码不是递归安全的

We could use a reference counter to correct this:

我们可以使用参考计数器来纠正这个问题:

struct MyStruct
{
    size_t c;
    P * p;

    void foo()
    {
        if (c == 0)
        {
            this->p = new P();
        }

        ++c;
        // lots of code, some using this->p
        --c;

        if (c == 0)
        {
            delete this->p;
            this->p = nullptr;
        }
    }
};

This way, the code becomes recursive-safe… But it is still not reentrant because of multithreading issues: We must be sure the modifications of cand of pwill be done atomically, using a recursivemutex (not all mutexes are recursive):

这样,代码变得递归安全……但由于多线程问题,它仍然不是可重入的:我们必须确保使用递归互斥锁(并非所有互斥锁都是递归的)以原子方式完成c和的修改:p

#include <mutex>

struct MyStruct
{
    std::recursive_mutex m;
    size_t c;
    P * p;

    void foo()
    {
        m.lock();

        if (c == 0)
        {
            this->p = new P();
        }

        ++c;
        m.unlock();
        // lots of code, some using this->p
        m.lock();
        --c;

        if (c == 0)
        {
            delete this->p;
            this->p = nullptr;
        }

        m.unlock();
    }
};

And of course, this all assumes the lots of codeis itself reentrant, including the use of p.

当然,这一切都假设lots of code本身是可重入的,包括使用p.

And the code above is not even remotely exception-safe, but this is another story… ^_^

上面的代码甚至不是远程异常安全的,但这是另一回事……^_^

7. Hey 99% of our code is not reentrant!

7. 嘿,我们 99% 的代码都是不可重入的!

It is quite true for spaghetti code. But if you partition correctly your code, you will avoid reentrancy problems.

意大利面条式代码确实如此。但是如果你正确地划分你的代码,你将避免重入问题。

7.1. Make sure all functions have NO state

7.1. 确保所有函数都没有状态

They must only use the parameters, their own local variables, other functions without state, and return copies of the data if they return at all.

它们必须只使用参数、它们自己的局部变量、其他没有状态的函数,如果它们返回,则返回数据的副本。

7.2. Make sure your object is "recursive-safe"

7.2. 确保您的对象是“递归安全的”

An object method has access to this, so it shares a state with all the methods of the same instance of the object.

对象方法可以访问this,因此它与对象的同一实例的所有方法共享一个状态。

So, make sure the object can be used at one point in the stack (i.e. calling method A), and then, at another point (i.e. calling method B), without corrupting the whole object. Design your object to make sure that upon exiting a method, the object is stable and correct (no dangling pointers, no contradicting member variables, etc.).

因此,请确保该对象可以在堆栈中的某一点使用(即调用方法 A),然后在另一点(即调用方法 B)使用,而不会破坏整个对象。设计您的对象以确保在退出方法时,该对象是稳定且正确的(没有悬空指针,没有相互矛盾的成员变量等)。

7.3. Make sure all your objects are correctly encapsulated

7.3. 确保所有对象都被正确封装

No one else should have access to their internal data:

其他人不应有权访问其内部数据:

    // bad
    int & MyObject::getCounter()
    {
        return this->counter;
    }

    // good
    int MyObject::getCounter()
    {
        return this->counter;
    }

    // good, too
    void MyObject::getCounter(int & p_counter)
    {
        p_counter = this->counter;
    }

Even returning a const reference could be dangerous if the user retrieves the address of the data, as some other portion of the code could modify it without the code holding the const reference being told.

如果用户检索数据的地址,即使返回 const 引用也可能是危险的,因为代码的其他部分可以修改它,而无需告知保存 const 引用的代码。

7.4. Make sure the user knows your object is not thread-safe

7.4. 确保用户知道您的对象不是线程安全的

Thus, the user is responsible to use mutexes to use an object shared between threads.

因此,用户负责使用互斥锁来使用线程间共享的对象。

The objects from the STL are designed to be not thread-safe (because of performance issues), and thus, if a user want to share a std::stringbetween two threads, the user must protect its access with concurrency primitives;

STL 中的对象被设计为不是线程安全的(因为性能问题),因此,如果用户想要std::string在两个线程之间共享一个,用户必须使用并发原语保护其访问;

7.5. Make sure your thread-safe code is recursive-safe

7.5. 确保您的线程安全代码是递归安全的

This means using recursive mutexes if you believe the same resource can be used twice by the same thread.

这意味着如果您认为同一资源可以被同一线程使用两次,请使用递归互斥锁。

回答by slacker

"Safely" is defined exactly as the common sense dictates - it means "doing its thing correctly without interfering with other things". The six points you cite quite clearly express the requirements to achieve that.

“安全”的定义与常识完全一致——它的意思是“正确地做事而不干扰其他事情”。您引用的六点非常清楚地表达了实现这一目标的要求。

The answers to your 3 questions is 3× "no".

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



Are all recursive functions reentrant?

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

NO!

不!

Two simultaneous invocations of a recursive function can easily screw up each other, if they access the same global/static data, for example.

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



Are all thread-safe functions reentrant?

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

NO!

不!

A function is thread-safe if it doesn't malfunction if called concurrently. But this can be achieved e.g. by using a mutex to block the execution of the second invocation until the first finishes, so only one invocation works at a time. Reentrancy means executing concurrently without interfering with other invocations.

如果一个函数在并发调用时不会发生故障,那么它就是线程安全的。但这可以通过例如使用互斥锁来阻止第二次调用的执行直到第一次调用完成来实现,因此一次只能进行一次调用。重入意味着并发执行而不干扰其他调用



Are all recursive and thread-safe functions reentrant?

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

NO!

不!

See above.

看上面。

回答by drawnonward

The common thread:

共同点:

Is the behavior well defined if the routine is called while it is interrupted?

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

If you have a function like this:

如果您有这样的功能:

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

Then it is not dependent upon any external state. The behavior is well defined.

那么它不依赖于任何外部状态。行为定义明确。

If you have a function like this:

如果您有这样的功能:

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

The result is not well defined on multiple threads. Information could be lost if the timing was just wrong.

结果在多线程上没有很好地定义。如果时间错了,信息可能会丢失。

The simplest form of a reentrant function is something that operates exclusively on the arguments passed and constant values. Anything else takes special handling or, often, is not reentrant. And of course the arguments must not reference mutable globals.

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

回答by Yttrill

Now I have to elaborate on my previous comment. @paercebal answer is incorrect. In the example code didn't anyone notice that the mutex which as supposed to be parameter wasn't actually passed in?

现在我必须详细说明我之前的评论。@paercebal 答案不正确。在示例代码中,没有人注意到应该是参数的互斥锁实际上没有传入吗?

I dispute the conclusion, I assert: for a function to be safe in the presence of concurrency it must be re-entrant. Therefore concurrent-safe (usually written thread-safe) implies re-entrant.

我对这个结论提出异议,我断言:对于一个在并发的情况下是安全的函数,它必须是可重入的。因此并发安全(通常写成线程安全)意味着可重入。

Neither thread safe nor re-entrant have anything to say about arguments: we're talking about concurrent execution of the function, which can still be unsafe if inappropriate parameters are used.

线程安全和可重入都没有关于参数的任何说法:我们谈论的是函数的并发执行,如果使用了不合适的参数,这仍然可能是不安全的。

For example, memcpy() is thread-safe and re-entrant (usually). Obviously it will not work as expected if called with pointers to the same targets from two different threads. That's the point of the SGI definition, placing the onus on the client to ensure accesses to the same data structure are synchronised by the client.

例如, memcpy() 是线程安全且可重入的(通常)。显然,如果使用来自两个不同线程的指向相同目标的指针进行调用,它将不会按预期工作。这就是 SGI 定义的重点,将责任放在客户端以确保对相同数据结构的访问由客户端同步。

It is important to understand that in general it is nonsenseto have thread-safe operation include the parameters. If you've done any database programming you will understand. The concept of what is "atomic" and might be protected by a mutex or some other technique is necessarily a user concept: processing a transaction on a database can require multiple un-interrupted modifications. Who can say which ones need to be kept in sync but the client programmer?

重要的是要理解,一般来说,让线程安全操作包含参数是无稽之谈。如果你做过任何数据库编程,你就会明白。什么是“原子”并且可能受互斥锁或其他一些技术保护的概念必然是一个用户概念:处理数据库上的事务可能需要多次不间断的修改。除了客户端程序员,谁能说哪些需要保持同步?

The point is that "corruption" doesn't have to be messing up the memory on your computer with unserialised writes: corruption can still occur even if all individual operations are serialised. It follows that when you're asking if a function is thread-safe, or re-entrant, the question means for all appropriately separated arguments: using coupled arguments does not constitute a counter-example.

关键是“损坏”不一定会用未序列化的写入弄乱计算机上的内存:即使所有单个操作都被序列化,损坏仍然可能发生。因此,当您询问函数是线程安全的还是可重入的时,问题意味着所有适当分离的参数:使用耦合参数并不构成反例。

There are many programming systems out there: Ocaml is one, and I think Python as well, which have lots of non-reentrant code in them, but which uses a global lock to interleave thread acesss. These systems are not re-entrant and they're not thread-safe or concurrent-safe, they operate safely simply because they prevent concurrency globally.

有许多编程系统:Ocaml 是其中之一,我认为 Python 也是如此,其中包含大量不可重入的代码,但它使用全局锁来交错线程访问。这些系统不是可重入的,也不是线程安全或并发安全的,它们运行安全只是因为它们在全局范围内防止并发。

A good example is malloc. It is not re-entrant and not thread-safe. This is because it has to access a global resource (the heap). Using locks doesn't make it safe: it's definitely not re-entrant. If the interface to malloc had be design properly it would be possible to make it re-entrant and thread-safe:

一个很好的例子是 malloc。它不是可重入的,也不是线程安全的。这是因为它必须访问全局资源(堆)。使用锁并不安全:它绝对不是可重入的。如果 malloc 的接口设计正确,则可以使其重入和线程安全:

malloc(heap*, size_t);

Now it can be safe because it transfers the responsibility for serialising shared access to a single heap to the client. In particular no work is required if there are separate heap objects. If a common heap is used, the client has to serialise access. Using a lock insidethe function is not enough: just consider a malloc locking a heap* and then a signal comes along and calls malloc on the same pointer: deadlock: the signal can't proceed, and the client can't either because it is interrupted.

现在它可以是安全的,因为它将序列化对单个堆的共享访问的责任转移到客户端。特别是如果有单独的堆对象,则不需要任何工作。如果使用公共堆,则客户端必须序列化访问。在函数内部使用锁是不够的:只考虑一个 malloc 锁定一个堆*,然后一个信号出现并在同一个指针上调用 malloc:死锁:信号不能继续,客户端也不能,因为它被打断。

Generally speaking, locks do not make things thread-safe .. they actually destroy safety by inappropriately trying to manage a resource that is owned by the client. Locking has to be done by the object manufacturer, thats the only code that knows how many objects are created and how they will be used.

一般来说,锁不会使事情成为线程安全的……它们实际上通过不恰当地尝试管理由客户端拥有的资源来破坏安全性。锁定必须由对象制造商完成,这是唯一知道创建了多少对象以及如何使用它们的代码。

回答by Clifford

The "common thread" (pun intended!?) amongst the points listed is that the function must not do anything that would affect the behaviour of any recursive or concurrent calls to the same function.

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

So for example static data is an issue because it is owned by all threads; if one call modifies a static variable the all threads use the modified data thus affecting their behaviour. Self modifying code (although rarely encountered, and in some cases prevented) would be a problem, because although there are multiple thread, there is only one copy of the code; the code is essential static data too.

因此,例如静态数据是一个问题,因为它由所有线程拥有;如果一个调用修改了一个静态变量,则所有线程都使用修改后的数据,从而影响它们的行为。自我修改代码(虽然很少遇到,在某些情况下被阻止)会是一个问题,因为虽然有多个线程,但代码只有一个副本;代码也是必不可少的静态数据。

Essentially to be re-entrant, each thread must be able to use the function as if it were the only user, and that is not the case if one thread can affect the behaviour of another in a non-deterministic manner. Primarily this involves each thread having either separate or constant data that the function works on.

从本质上讲,要重入,每个线程都必须能够像唯一的用户一样使用该函数,如果一个线程可以以不确定的方式影响另一个线程的行为,则情况并非如此。这主要涉及每个线程具有函数处理的单独或恒定数据。

All that said, point (1) is not necessarily true; for example, you might legitimately and by design use a static variable to retain a recursion count to guard against excessive recursion or to profile an algorithm.

综上所述,第 (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!).

线程安全函数不需要可重入;它可以通过使用锁专门防止重入来实现线程安全,并且第 (6) 点表示这样的函数是不可重入的。关于第 (6) 点,调用锁定的线程安全函数的函数在递归中使用是不安全的(它将死锁),因此不被称为可重入的,尽管它对于并发可能仍然安全,并且仍然是重入的,因为多个线程可以同时在这样的函数中拥有它们的程序计数器(只是不是锁定区域)。可能这有助于区分线程安全与可重入性(或者可能会增加您的困惑!)。

回答by ChrisF

The answers your "Also" questions are "No", "No" and "No". Just because a function is recursive and/or thread safe it doesn't make it re-entrant.

您的“也”问题的答案是“否”、“否”和“否”。仅仅因为一个函数是递归的和/或线程安全的,它不会使它重入。

Each of these type of function can fail on all the points you quote. (Though I'm not 100% certain of point 5).

这些类型的功能中的每一种都可能在您引用的所有点上失败。(虽然我不是 100% 确定第 5 点)。

回答by Joe Soul-bringer

The terms "Thread-safe" and "re-entrant" mean only and exactly what their definitions say. "Safe" in this context means onlywhat the definition you quote below it says.

术语“线程安全”和“可重入”仅指它们的定义所说的内容。在此上下文中,“安全”表示您在其下方引用的定义。

"Safe" here certainly doesn't mean safe in the broader sense that calling a given function in a given context won't totally hose your application. Altogether, a function might reliably produce a desired effect in your multi-threaded application but not qualify as either re-entrant or thread-safe according to the definitions. Oppositely, you can call re-entrant functions in ways that will produce a variety of undesired, unexpected and/or unpredictable effects in your multi-threaded application.

这里的“安全”当然并不意味着在更广泛的意义上安全,即在给定的上下文中调用给定的函数不会完全控制您的应用程序。总而言之,一个函数可能会在您的多线程应用程序中可靠地产生所需的效果,但根据定义不符合可重入或线程安全的条件。相反,您可以通过在多线程应用程序中产生各种不希望的、意外的和/或不可预测的效果的方式调用重入函数。

Recursive function can be anything and Re-entrant has a stronger definition than thread-safe so the answers to your numbered questions are all no.

递归函数可以是任何东西,而 Re-entrant 的定义比线程安全的要强,所以你的编号问题的答案都是否定的。

Reading the definition of re-entrant, one might summarize it as meaning a function which will not modify any anything beyond what you call it to modify. But you shouldn't rely on only the summary.

阅读可重入的定义,人们可能会将其概括为一个函数,除了您调用它要修改的内容外,它不会修改任何任何内容。但是你不应该只依赖摘要。

Multi-threaded programming is just extremely difficultin the general case. Knowing which part of one's code re-entrant is only a part of this challenge. Thread safety is not additive. Rather than trying to piece together re-entrant functions, it's better to use an overall thread-safedesign patternand use this pattern to guide your use of everythread and shared resources in the your program.

多线程编程在一般情况下是极其困难的。知道代码的哪一部分可重入只是这个挑战的一部分。线程安全不是附加的。与其试图将可重入函数拼凑在一起,不如使用整体线程安全设计模式并使用此模式来指导您对程序中每个线程和共享资源的使用。