可重入函数与KEILC51中的可重入函数 keil uvision4 c51

该文章是从多个文章中,根据个人的理解,进行了引用,在此特声明,表示感谢。

一、可重入函数

1.reentrant

可重入的,主要用于多任务系统中。“可重入函数可以被一个以上的任务调用,而不必担心数据被破坏。可重入函数任何时候都可以被中断,一段时间以后又可以运行,而相应的数据不会丢失。”(摘自嵌入式实时操作系统uC/OS-II)

一个可重入的函数。简单理解为可以被中断的函数。就是说,你可以在这个函数执行的任何时候中断他的运行,在任务调度下去执行另外一段代码而不会出现什么错误。而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等等,所以他如果被中断的话,可能出现问题,这类函数是不能运行在多任务环境下的。

示例:假设Exam是int型全局变量,函数Squre_Exam返回Exam平方值。那么如下函数不具有可重入性。

unsigned int example( int para)

{

unsigned int temp;
Exam = para;//(**)
temp =Square_Exam( );
returntemp;
}
此函数若被多个进程调用的话,其结果可能是未知的,因为当(**)语句刚执行完后,另外一个使用本函数的进程可能正好被激活,那么当新激活的进程执行到此函数时,将使Exam赋与另一个不同的para值,所以当控制重新回到“temp= Square_Exam( )”后,计算出的temp很可能不是预想中的结果。

重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外不依赖于任何环境(包括static),这样的函数就是purecode(纯代码)可重入,可以允许有该函数的多个副本在运行,由于它们使用的是分离的栈,所以不会互相干扰。如果确实需要访问全局变量(包括static),一定要注意实施互斥手段。可重入函数在并行运行环境中非常重要,但是一般要为访问全局变量付出一些性能代价。

编写可重入函数时,若使用全局变量,则应通过关中断、信号量(即P、V操作)等手段对其加以保护。

上面的程序可以修改为如下程序,就可重入

unsigned int example( int para ) {
可重入函数与KEILC51中的可重入函数 keil uvision4 c51
unsigned inttemp;
[申请信号量操作]//(1)
Exam =para;
temp =Square_Exam( );
[释放信号量操作]
returntemp;
}
(1)若申请不到“信号量”,说明另外的进程正处于给Exam赋值并计算其平方过程中(即正在使用此信号),本进程必须等待其释放信号后,才可继续执行。若申请到信号,则可继续执行,但其它进程必须等待本进程释放信号量后,才能再使用本信号。

保证函数的可重入性的方法:
在写函数时候尽量使用局部变量(例如寄存器、堆栈中的变量),对于要使用的全局变量要加以保护(如采取关中断、信号量等方法),这样构成的函数就一定是一个可重入的函数。

  基本上下面的函数是不可重入的

  (1)函数体内使用了静态的数据结构;

  (2)函数体内调用了malloc()或者free()函数;

  (3)函数体内调用了标准I/O函数。

下面举例加以说明。
A.可重入函数
voidstrcpy(char *lpszDest, char *lpszSrc)

{
while(*lpszDest++=*lpszSrc++);
*dest=0;
}

B.不可重入函数1
charcTemp;//全局变量
voidSwapChar1(char *lpcX, char *lpcY)

{
cTemp=*lpcX;
*lpcX=*lpcY;
lpcY=cTemp;//访问了全局变量
}

C.不可重入函数2
voidSwapChar2(char *lpcX,char *lpcY)

{
static charcTemp;//静态局部变量
cTemp=*lpcX;
*lpcX=*lpcY;
lpcY=cTemp;//使用了静态局部变量
}

当然,有些时候,在函数中是必须要使用static变量的,比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。

  把一个不可重入函数变成可重入的唯一方法是用可重入规则来重写他。

  其实很简单,只要遵守了几条很容易理解的规则,那么写出来的函数就是可重入的。

  第一,不要使用全局变量。因为别的代码很可能覆盖这些变量值。

  第二,在和硬件发生交互的时候,切记执行类似disinterrupt()之类的操作,就是关闭硬件中断。完成交互记得打开中断,在有些系列上,这叫做“进入/退出核心”或者用OS_ENTER_KERNAL/OS_EXIT_KERNAL来描述。//这是临界区保护

  第三,不能调用任何不可重入的函数。

  第四,谨慎使用堆栈。最好先在使用前先OS_ENTER_KERNAL。

  还有一些规则,都是很好理解的,总之,时刻记住一句话:保证中断是安全的!

二、C51中的可重入函数

1、C51中需要重入函数的原因

在其它环境下(比如PC,比如ARM),函数重入的问题一般不是要特别注意的问题.只要你没有使用static变量,或者指向static变量的指针,一般情况下,函数自然而然地就是可重入的.

但C51不一样,如果你不特别设计你的函数,它就是不可重入的。引起这个情况的原因是:

一般的C编译器是将局部变量放入栈中,而C51是将其放入内部RAM,开辟一片存储空间,多个函数共享该覆盖区。该区域在编译链接时已定位。各函数之间没有直接或间接的调用关系,则其局部变量空间便可覆盖。如果一个函数同时被多个函数调用,可能会造成某些变量会被冲掉。因此C51中的函数基本上都是不可重入的。

2、可重入函数

对于不可重入的函数通过加reentrant来声明为可重入。

函数说明: 函数名(形式参数表)reentrant声明为可重入函数

首先是Keil官网上对reentrant函数的解释。

http://www.keil.com/support/man/docs/c51/c51_le_reentrantfuncs.htm

A reentrant function may be shared by several processes at the sametime. When a reentrant function is executing, another process caninterrupt the execution and then begin to execute that samereentrant function.

Normally, functions in Cx51 cannot be called recursively or in afashion which causes reentrancy. The reason for this limitation isthat function arguments and local variables are stored in fixedmemory locations. Recursive calls to the function use the samememory locations. And, in this case,arguments andlocals would get corrupted.

Thereentrantfunctionattribute allows you to declare functions that may be reentrantand, therefore, may be called recursively. For example:

int calc (char i, int b) reentrant 
{ int x;
 x = table [i]; 
return (x * b); }

Reentrant functions can be called recursively and can becalledsimultaneouslybytwo or more processes.Reentrant functions are often required inreal-time applications or in situations where interrupt code andnon-interrupt code must share a function.

As in the above example, you may selectively define (usingthereentrantattribute)functions as being reentrant. For each reentrant function, areentrant stack area is simulated in internal or external memorydepending upon the memory model used, as follows:

Reentrant functions use the default memory model to determine whichmemory space to use for the reentrant stack. You may specify (withthesmall,compact,andlargefunctionattributes) which memory model to use for a function. RefertoSpecifying the Memory Model for aFunctionfor more information aboutmemory models and function declarations.

The following rules apply to functions declared withthereentrantattribute.

The reentrant stack simulation architecture is inefficient, butnecessarydueto a lack of suitable addressing methods available on the8051. For this reason, use reentrant functionssparingly.

The simulated stack used by reentrant functions has its own stackpointer which is independent of the 8051 stack and stack pointer.The stack and stack pointer are defined and initialized intheSTARTUP.A51file.

The following table details the stack pointer assembler variablename, data area, and size for each of the three memory models.

ModelPointerStack Information
SMALL?C_IBP
(1 Byte)
The stack is located in indirectly accessibleinternal memory (idata). The maximum reentrant stack size is 256bytes. To access the small reentrant stack, R0 or R1 is loaded withthe value of ?C_IBP and the reentrant stack is accessed indirectlyusing the MOVA,@R0/@R1 andMOV@R0/@R1,A instructions.
COMPACT?C_PBP
(1 Byte)
The stack is located in Page-addressable externalmemory (pdata). The maximum reentrant stack size is 256 bytes. Toaccess the compact reentrant stack, R0 or R1 is loaded with thevalue of ?C_PBP and the reentrant stack is accessed indirectlyusing the MOVXA,@R0/@R1 andMOVX@R0/@R1,Ainstructions.
LARGE?C_XBP
(2 Bytes)
The stack is located in Externally accessible memory(xdata). The maximum reentrant stack size is 64K Bytes. To accessthe large reentrant stack, DPTR is loaded with the value of ?C_XBPand the reentrant stack is accessed indirectly using theMOVXA,@DPTR andMOVX@DPTR,A instructions.

The simulated stack area for reentrant functions isorganizedfrom top to bottom—it stacksdown.The 8051 hardware stack is just theopposite and is organized bottom to top—it stacks up. Whenusing theSMALLmemory model, boththe simulated stack and the 8051 hardware stack share the samememory area but grow towards each other.

The simulated stack and stack pointers are declared and initializedin the Cx51 Compiler startup codeinSTARTUP.A51which can be foundintheLIBsubdirectory.Youmust modify the startup code to specify which simulated stack(s) toinitialize in order to use reentrantfunctions.You can also modify the startingaddress for the top of the simulated stack(s) in the startup code.Refer toSTARTUP.A51formore information on reentrant function stack areas.

When calling a function with a reentrant stack, the compiler MUSTknow that the function has a reentrant stack. The compiler figuresthis out from the function prototype which should include thereentrant keyword (just like the function definition). The compilermust also know the memory model used by the function (to determinewhich reentrant stack to stuff arguments on). This is determinedeither from the memory model specified for the function, or thememory model specified to the compiler, or from the default memorymodel (small).

To pass arguments, the compiler generates code that decrements thestack pointer and then "pushes" arguments onto the stack by storingthe argument indirectly through R0/R1 or DPTR.

When a reentrant function is called, it decreases the stack pointer(for local variables) and accesses arguments using the stackpointer plus an offset (which corresponds to the number of bytes oflocal variables).

When a reentrant function returns, it adjusts the stack pointer tothe value before arguments were pushed. So the caller does not needto perform any stack adjustment after calling a reentrantfunction.

注意事项:
1、再入函数不能传递bit类型参数。
2、与PL/M51兼容的函数不能具有reentrant,这样也不能调用再入函数。
3、在编译时:再入函数建立的是模拟堆栈区,small模式下模拟堆栈区位于idata区,compact模式下模拟堆栈区位于pdata区,large模式下模拟堆栈区位于xdata区.
4、在同一程序中可以定义和使用不同存储器模式的再入函数,任意模式的再入函数不能调用不同存储器模式的再入函数,但可以调用普通函数。
5、实际参数可以传递给间接调用的再入函数。无再入属性的间接调用函数不能包含调用参数。

由于每一次调用reentrant函数都要把函数的参数和局部变量入栈,容易造成栈溢出。

对于C51可重入函数的详细解析,见转载的文章《KEILC51可重入函数及模拟栈浅析

  

爱华网本文地址 » http://www.413yy.cn/a/25101013/168029.html

更多阅读

visio2003字号与word中的字号对应关系 小四对应的字号

visio2003字号与word中的字号对应关系用visio2003作了一个图,插入到word中,要求图中字体大小为6号字,可visio中字体大小只有6pt,不知道是不是对应的6号字,请问word与visio字体是如何对应的?在印刷出版上,中文字号制与点数制的对照关系如下:{

第29节:第二站:与4A中的贵族闪婚闪离

系列专题:《职场如何赚到封顶高薪:别被office干掉》  第二站:与4A中的贵族闪婚闪离  4A相当于广告公司中的贵族,"J"---相当于4A中的贵族。  "J"是传说中最适合养老的公司,传说中福利最好的公司,传说中人员流动最小的公司,传说中拿

声明:《可重入函数与KEILC51中的可重入函数 keil uvision4 c51》为网友亽故事分享!如侵犯到您的合法权益请联系我们删除