1

What is the significance of having a function reentrant in a single-threaded environment?

I understood that for a function to be reentrant it needs to be able to be interrupted, entered by another thread, and resume without having any undefined or undesired side effects.

I read this question Threadsafe vs re-entrant. But it's not clear how can this actually happen in code:

you can have reentrance problems in a single-threaded program if you use callbacks or recursive functions.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Noor Yag
  • 43
  • 7
  • A recursive function can be reentrant and single thread, without using interrupts. – Weather Vane Dec 20 '20 at 12:24
  • 1
    The function can call itself (perhaps with an intermediate function). Also, environments with interrupts are usually described as single-threaded. – M.M Dec 20 '20 at 12:26
  • From what I vaguely recall, if you work in Windows, you can have procedures that are called on a waitable timer being signaled, even though the program may be single-threaded. So imagine if you have a timer that goes off every half-second to call your timer procedure, but it takes your timer procedure on average 1 second to complete. So the timer proc needs to be re-entrant safe. – PaulMcKenzie Dec 20 '20 at 12:48
  • @PaulMcKenzie interesting example, but then wouldn't the fact that it is single threaded mean that it will anyways have to wait until the function call is done, in order to call it again? – Noor Yag Dec 21 '20 at 05:56

2 Answers2

1

Suppose we put multi-threading aside. This function can be said to be non re-entrant:

void bar() {
    static bool inside_function;
    inside_function = true;
    
    assert (inside_function == true)

    inside_function = false;
}

Without recursion and callbacks this isn't an issue. Though once you add recursion the non-re-entrancy of the function matters:

void foo(bool repeat = true) {
    static bool inside_function;
    inside_function = true;
    
    if (repeat) foo(false);

    // do some stuff
    // assert( inside_function == true )
    std::cout << inside_function << "\n";

    inside_function = false;
}

Suppose do some stuff depends on inside_function == true, then this recursion fails (output is 1 0). Note that this is a contrived example for illustration and with callbacks the issue is not always that obvious:

struct Foo {
    bool inside = false;
    void operator()(Foo& f,bool call = true) {
        inside = true;

        if(call) f(*this,false);

        std::cout << "inside operator() : " << inside  << "\n";
        if (inside == false) std::cout << "something went wrong !!!\n";             

        inside = false;
    }
};

int main() {
    Foo f;
    f(f);
}

Output:

inside operator() : 1
inside operator() : 0
something went wrong !!!

In a single threaded environment thread-safety is not an issue, but re-entrancy is when recursion or callbacks are used.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
0

Interrupts. They are asynchronous with the normal execution and calling a function both in an interrupt handler and outside of that handler results in the function being re entered. Within an operating system in a user space program, you don't deal with interrupts directly, but with signals triggered by the operating system.

In C++20, calling functions within coroutines may cause similar re entrancy.

Lastly, recursion is another form of re entrancy.

eerorika
  • 232,697
  • 12
  • 197
  • 326