Properties of Reentrant Function
There are several properties of the Reentrant function in C. Some main properties of the Reentrant function are as follows:
- It will not use global and static data . Although there are no limits, it is generally not recommended. It is because restarting the reentrant function with the new data could have unintended consequences, and the interrupt could change some global settings.
- It shouldn't alter its own source code . It is crucial since the function's action should be consistent across the code. But it would be acceptable if the interrupt procedure utilizes a local copy of the reentrant function each time it uses a different value or before and after the interrupt.
- The re-entrant function may not call any additional non-reentrant functions or routines with synchronization.
Examples of Reentrant Function
Here, we will explore various instances of Reentrant function in C along with their elucidation:
Example: 1
strtok:
A string can be segmented into smaller parts based on a delimiter by utilizing the strtok function. This function is considered non-thread-safe due to its reliance on a static pointer to maintain its internal state. To address this, developers can opt for the reentrant version strtok_r, which allows for safe use in threaded environments. Another approach is to manage the state externally, such as by employing distinct data structures for individual threads, or combining both methods for enhanced safety.
Code:
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello,world,this,is,a,test";
char *token, *saveptr;
token = strtok_r(str, ",", &saveptr);
while (token != NULL) {
printf("Token: %s\n", token);
token = strtok_r(NULL, ",", &saveptr);
}
return 0;
}
Output:
Token: Hello
Token: world
Token: this
Token: is
Token: a
Token: test
Example: 2
qsort:
The QuickSort algorithm is applied for sorting an array through the qsort function. The sequence of elements is established solely through a comparison function. By default, the qsort function is not reentrant because of its shared workspace. However, it can be made reentrant by supplying a personalized comparison function along with a context that holds extra information necessary for the sorting process.
Code:
#include <stdio.h>
#include <stdlib.h>
int compare_integers(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
int main() {
int arr[] = { 5, 2, 8, 1, 6 };
int n = sizeof(arr) / sizeof(arr[0]);
qsort(arr, n, sizeof(int), compare_integers);
for (int i = 0; i< n; i++) {
printf("%d ", arr[i]);
}
return 0;
}
Output:
1 2 5 6 8
Example: 3
rand:
The rand function generates a pseudo-random integer. To make it reentrant, you can utilize the rand_r function, which requires a pointer to an unsigned int as a seed. Despite not being thread-safe by default because of shared internal data, this reentrant version allows for reentrancy.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
unsigned int seed = time(NULL);
int i;
for (i = 0; i< 5; i++) {
printf("Random Number: %d\n", rand_r(&seed));
}
return 0;
}
Output:
Random Number: 212005489
Random Number: 2042157013
Random Number: 2068794670
Random Number: 1367026107
Random Number: 927415125
Note that:- These numbers will vary every time you run the code.
Conclusion:
In summary, reentrant functions play a vital role in ensuring the effective and safe operation of multi-threaded applications in C. They allow multiple threads to call the same function concurrently without causing unintended conflicts or data integrity issues. By maintaining separate local data for each thread and avoiding shared resources, reentrant functions promote efficient parallelism and simplify synchronization mechanisms.