What is a reentrant function in C/C++?

Do you know what is a reentrant function?

Where you should use the reentrant function in your code or how to write a thread-safe function?

In this blog post, you will learn what a reentrant function is and how to know which function is a reentrant function. I am assuming here you are already familiar with the C functions. But still, if you are not, then it is my suggestion to read the C function first.

Reentrant Function:

A function is called reentrant if it can be interrupted in the middle of its execution and then safely be called again (“re-entered”) before its previous invocations complete execution.

Interruption could be caused by an internal action such as a jump or call, or by an external action such as an interrupt or signal. Once the reentered invocation completes, the previous invocations will resume correct execution.

A reentrant subroutine (function) can be invoked multiple times and safely run concurrently on multiple processors, or on a single processor system. Also, it can achieve thread safety, but being reentrant alone might not be sufficient to be thread-safe in all situations. It means all thread safer code does not necessarily have to be reentrant.

Example of Reentrant Functions:

The following functions foo1() and foo2() are reentrant functions. If an interrupt comes and pauses their execution and shifts the control to another piece of the code, then once control comes to these functions they will be working as expected.

// Both foo1() and foo2() are reentrant functions
int foo1(int i)
{
    return i * 5;
}

int foo2(int i)
{
    return foo1(i) * 5;
}

 

Example of Non-Reentrant Functions:

In the following code, both fun1() and fun2() are not reentrant functions. Now you are thinking why I am saying that both are reentrant functions; the reason behind that the fun1() depends on ‘data‘ (non-const global variable). If fun1() is interrupted during execution by an interrupt that modifies ‘data’, then reentry into fun1() will return the wrong value of the ‘data‘ and you can not get the expected value. Hence, fun1 is not reentrant. Also because fun2 calls the fun1; thus fun2 is also not a reentrant.

int data = 10;

int fun1()
{
    data += 2;
    return data;
}

int fun2()
{
    return fun1() + 2;
}

 

 

Some General conditions to be reentrant:

1. It may not use any static or global non-constant data without synchronization. Also shared variables should be accessed in an atomic way.

2. It does not call non-reentrant functions.

3. It may not modify itself without synchronization.

4. It does not use the hardware in a non-atomic way.

 

FAQ  Related to Reentrant Function in C/C++:

1. Are all recursive functions reentrant?

You can not say blindly all recursive functions are reentrant.

In a multithreaded application, if a recursive function accesses the shared resources without using any proper synchronization techniques, the behavior could be undefined; if called by multiple threads at the same moment.

 

2. Are all thread-safe functions reentrant?

No.

It is not necessary that all thread-safe function is reentrant function. Consider the below example, where we make the swap function thread-safe by making ‘data’ thread-local. The swap function is thread-safe here but it still fails to be reentrant.  The ‘data‘ will create a problem if isr() is called in the same context as a thread already executing swap():

_Thread_local int data;

void swap(int* a, int* b)
{
    data = *a;
    *a = *b;
    /* 
        Hardware interrupt
       might invoke isr() here.
    */
    *b = data;
}

void isr()
{
    int a = 27, b = 6;
    swap(&a, &b);
}

 

3. Are all reentrant functions are thread-safe functions?

No.

Are all recursive and thread-safe functions reentrant?

 

Recommended Page for you:

 

(Source: https://en.wikipedia.org/wiki/Reentrancy_(computing))