Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread safety vs Re entrancy

I know this has been discussed a lot in this forum. But one thing still confuses me. Wikipedia mentions that every re entrant code is thread safe. http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29 And later on gives an example of a function which is re entrant but not thread safe.

int t;

void swap(int *x, int *y)
{
    int s;

    s = t;  // save global variable
    t = *x;
    *x = *y;
    // hardware interrupt might invoke isr() here!
    *y = t;
    t = s;  // restore global variable
}

void isr()
{
    int x = 1, y = 2;
    swap(&x, &y);
}

This confuses me. Are all re entrant codes thread safe? Also, are all recursive function thread safe. I am not able to visualize the difference.

Thanks

like image 423
Deepti Jain Avatar asked Feb 25 '12 03:02

Deepti Jain


2 Answers

The concepts of re-entrancy and thread safety are related, but not equivalent. You can write a re-entrant function that is not thread-safe, and a thread-safe function that is not re-entrant. I will use C# for my examples:

Re-entrant Function that is not Thread-Safe

This function reverses the entries of an array:

void Reverse(int[] data) {
    if (data == null || data.Length < 2) return;
    for (var i = 0 ; i != data.Length/2 ; i++) {
        int tmp = data[i];
        data[i] = data[data.Length-i-1];
        data[data.Length-i-1] = tmp;
    }
}

This function is clearly re-entrant, because it does not reference outside resources. Its thread safety, however, is conditional upon not passing it the same data from multiple threads. If several threads concurrently pass Reverse the same instance of an array, an incorrect result may be produced. One way of making this function unconditionally thread-safe would be an addition of a lock:

void Reverse(int[] data) {
    if (data == null || data.Length < 2) return;
    lock (data) {
        for (var i = 0 ; i != data.Length/2 ; i++) {
            int tmp = data[i];
            data[i] = data[data.Length-i-1];
            data[data.Length-i-1] = tmp;
        }
    }
}

Thread-Safe Function that is not Re-Entrant

This function calls function f() c times, and returns the value that has been returned more times than other values.

static int[] counts = new int[65536];

unsigned short MaxCount(Func<unsigned short> f, int c) {
    lock(counts) {
        Array.Clear(counts, 0, counts.Length);
        for (var i = 0 ; i != c ; i++) {
            counts[f()]++;
        }
        unsigned short res = 0;
        for (var i = 1 ; i != counts.Length ; i++) {
            if (counts[i] > counts[res]) {
                res = i;
            }
        }
        return res;
    }
}

This function is thread-safe, because it locks the static array that it uses to do the counting. However, it is not re-entrant: for example, if the functor f passed in were to call MaxCount, wrong results would be returned.

like image 138
Sergey Kalinichenko Avatar answered Oct 12 '22 10:10

Sergey Kalinichenko


Are all re entrant codes thread safe?

No.

Later in the Wikipedia article: …The key for avoiding confusion is that reentrant refers to only one thread executing. It is a concept from the time when no multitasking operating systems existed.

In other words, the concept of reentrance is oblivious to multithreaded execution (as the most common example). Only if that is an actual constraint in your system, then yes, reentrant would qualify as thread safe (but there would also be only one thread in that environment).

IMO, the term "reentrant" should be used only in the context of qualifying systems (does not apply to your desktop OS, but would apply to some embedded systems).

Now, if you really want to force use of the word 'reentrance' into a multithreaded environment: You could enforce reentrance in a multithreaded system only if you also guaranteed that it is also threadsafe. Perhaps a better question to ask would be "In order to guarantee reentrance in a multithreaded context, would that imply the function and all data it refers to also needs to be threadsafe?" - A: Yes, the function and everything it refers to would also need to be threadsafe and reentrant for the function to be reentrant in that context. Achieving this quickly becomes complex, and is a reason global variables are not a good idea.

Also, are all recursive function thread safe.

No.

like image 24
justin Avatar answered Oct 12 '22 10:10

justin