One, POSIX definitions of both reentrant and thread-safe concepts:
Reentrant Function:a Function whose effect when called by two or over threads,is to as if
The threads each executed the function one over another in a undefined order, even if the actual execution is Interleave D.
Thread-safe function:a Function is safely invoked concurrently by multiple threads.
Async-signal-safe function:a Function is invoked, without restriction from signal-catching functions. No function is Async-signal-safe unless explicitly described as such.
The relationship between the above three is: a reentrant function is necessarily a thread-safe function and an asynchronous signaling security function; A thread-safe function is not necessarily a reentrant function.
The difference between reentrant and thread-safe is embodied in the question of whether a reentrant function can be invoked safely in the Signal handler in the Signal handler function, and therefore also the Async-signal-safe function While the thread-safe function does not guarantee that it can be invoked securely in the Signal handler, it is also a async-signal-safe function if it is guaranteed that a non reentrant functions are not interrupted by a signal blocking set.
For example, Strtok is neither reentrant nor thread-safe, and strtok is not reentrant, but thread-safe, while Strtok_r is both reentrant and thread-safe. That is, if a function uses a static variable, it can be turned into a thread-safe function by adding a lock, but it may still not be reentrant. The alloc we know is also thread-safe but not reentrant.
For example, suppose that a function func () needs to access a shared resource during execution, so in order to achieve thread safety, lock the resource before using it, without needing to unlock the resource. Assuming that the function is in the process of executing a after the resource lock has been obtained, there is an asynchronous signal happening, the execution flow of the program is given to the corresponding signal processing function, and assuming that the function func () is also required in the signal processing function, then func () will still attempt to acquire the resource lock before accessing the shared resource in this execution. However, we know that the previous func () instance has already acquired the lock, thus the signal processing function is blocked; On the other hand, a thread that is interrupted by a signal processing function is unable to resume execution, and of course there is no chance of releasing the resource, so there is a deadlock between the thread and the signal handler function.
Therefore, func () is not reentrant, although it is guaranteed to be thread-safe by means of a lock, but because the function body accesses the shared resource.
In this case, the method used is generally to block a certain signal in a specific area.
Second, can be reentrant function
We know that when the signal is captured, no matter where the main control flow of the process is currently executing, it jumps to the signal processing function to execute, returning from the signal processing function before proceeding with the main control process. A signal processing function is a separate control process because it is asynchronous with the main control flow, and there is no relationship between invocation and invocation, and different stack spaces are used. A signal processing function is introduced to enable a process to have multiple control processes, and if these control processes access the same global resources (global variables, hardware resources, etc.), conflicts may occur, as shown in the following example.