Lets first understand the meaning of these two -
Re-entrancy: no global only local variables.
Thread-Safety: it is not possible for more then one threads to conflict with each other.
Now coming to the difference:
A function is "thread-safe" is its critical section is accessed/modified by only one thread at a time and rest of the other thread would wait to get a release before using it. While a function is re-entrant if it can be processed while the function is already in progressing.
Check the following example:
int length = 0;
char *s = NULL;
void AddToString(int ch)
{
StartCriticalSection(&CriticalSection);
char *newString = realloc(s, (length+1) * sizeof(char));
if (newString) {
if (ch == '\0' || ch == '\\') {
AddToString('\\'); // escape prefix
}
newString[length++] = ch;
newString[length] = '\0';
s = newString;
}
StopCriticalSection(&CriticalSection);
}
Above function is thread safe as critical section is guarded and only accessed by one thread at a time but not re-entrant because use of global variable.