Refer to various documents on the Self-network:
A reentrant function is simply a function that can be interrupted. That is to say, it can be interrupted at any time during function execution and transferred to the OS for scheduling to execute another piece of code, the return control function does not produce any errors. The non-reentrant function uses some system resources, such as the global variable area and the interrupt vector table. If it is interrupted, problems may occur. Such functions cannot run in multi-task environments.
It can also be understood that re-entry means repeated entry. First, it means that this function can be interrupted, second, it means that it does not depend on any environment (including static) except the variables on its own stack. Such a function is a purecode (pure code) reentrant, multiple copies of the function can be allowed to run. Since they use a separate stack, they do not interfere with each other. If you really need to access global variables (including static), be sure to implement mutex. Reentrant functions are very important in parallel runtime environments, but they generally cost some performance for accessing global variables.
When writing reentrant functions, if global variables are used, they should be protected by means of clearance interruption and semaphores (namely, P and V Operations.
Note: If the global variables used are not protected, this function is not reentrant. That is, when multiple processes call this function, it is very likely that the related global variables are changed to an unknown state.
Example: If Exam is an int type global variable, the function Squre_Exam returns the Exam square value. The following functions are not reentrant.
unsigned int example( int para ) { unsigned int temp; Exam = para; // (**) temp = Square_Exam( ); return temp; }
If the function is called by multiple processes, the result may be unknown, because after the (**) Statement is executed, another process that uses this function may be activated. When a newly activated process executes this function, Exam is assigned a different para value, so when the control returns "temp = Square_Exam ()", the calculated temp may not be the expected result. This function should be improved as follows.
Unsigned int example (int para) {unsigned int temp; [applying for semaphore operations] // (1) Exam = para; temp = Square_Exam (); [release semaphores] return temp ;}
(1) If the "semaphore" is not applied, it means that another process is assigning a value to Exam and calculating its square process (that is, this signal is being used ), this process can be executed only after it has released the signal. If the signal is applied for, you can continue to execute, but other processes must wait for this process to release the semaphore before using this signal.
Methods To ensure the reusability of functions:
When writing a function, try to use local variables (such as registers and variables in the stack). The global variables to be used should be protected (for example, using methods such as Guanzhong disconnection and semaphores ), this function must be a reentrant function.
The reentrant technologies adopted in VxWorks include:
* Dynamic stack variables (each sub-function has its own stack space)
* Protected global variables and static variables
* Task Variables
In the real-time system design, multiple tasks often call the same function. If this function is unfortunately designed as a non-reentrant function, different tasks may modify the data of other tasks calling this function when calling this function, resulting in unpredictable consequences. So what is a reentrant function? A reentrant function is a process that can be called by multiple tasks. When a task is called, you do not have to worry about data errors. Non-reentrant functions are considered unsafe functions in real-time system design. Most functions that meet the following conditions cannot be reentrant:
1) The function uses a static data structure;
2) the malloc () or free () function is called in the function body;
3) standard I/O functions are called in the function body.
The following is an example.
A. reentrant function
void strcpy(char *lpszDest, char *lpszSrc){ while(*lpszDest++=*lpszSrc++); *dest=0; }
B. function 1 cannot be reloaded.
CharcTemp; // global Variable void SwapChar1 (char * lpcX, char * lpcY) {cTemp = * lpcX; * lpcX = * lpcY; lpcY = cTemp; // The global variable is accessed}
C. function 2 cannot be reloaded.
Void SwapChar2 (char * lpcX, char * lpcY) {static char cTemp; // static local variable cTemp = * lpcX; * lpcX = * lpcY; lpcY = cTemp; // static local variables are used}
Question 1: How do I compile a reentrant function?
A: The global variables and static local variables are not accessed in the function body. If you stick to using only local variables, the written functions are reentrant. If you must access global variables, remember to use mutex semaphores to protect global variables.
Question 2: How can I rewrite a non-reentrant function to a reentrant function?
A: The only way to turn a non-reentrant function into a reentrant is to rewrite it using the reentrant rule. In fact, it is very simple. As long as there are several rules that are easy to understand, the written functions are reentrant.
1) do not use global variables. Because other code may overwrite these variable values.
2) when interacting with the hardware, remember to perform operations like disinterrupt (), that is, disable hardware interruption. When interaction is completed, remember to open the interrupt. In some series, this is called "Enter/exit core ".
3) You cannot call any other function that cannot be reentrant.
4) use the stack with caution. OS _ENTER_KERNAL is recommended before use.
Stack operations involve memory allocation. If you do not care about it, it will cause benefits and overwrite the data of other tasks. Therefore, please use the stack with caution! It is best not to use it! Many hackers use this to easily gain control of the system by executing illegal code. There are also some rules. In short, remember one sentence at a time to ensure that interruption is safe!
Instance question: I have designed a function such as the next function. A bug is prompted during code inspection because this function cannot be reentrant. Why?
Unsigned int sum_int (unsigned int base) {unsigned int index; static unsigned int sum = 0; // note that it is of the static type for (index = 1; index <= base; index ++) sum + = index; return sum ;}
Analysis: the so-called function is reentrant (or predictable), that is, the same output should be generated as long as the input data is the same. This function is unpredictable because it uses static variables. Because of the characteristics of static variables, such a function is called a function with the "internal memory" function. Therefore, if you need a reentrant function, you must avoid using static variables in the function. The principle is that you do not need to use static variables as much as possible.
Change the preceding function to a reentrant function. If the static keyword in the declared sum variable is removed, the variable sum is changed to an auto variable, and the function is changed to a reentrant function.
Of course, in some cases, static variables must be used in functions. For example, when a function returns a pointer type, the address of a static local variable must be used as the return value, if it is of the auto type, an error pointer is returned.