目录
可重入函数和不可重入函数:
基于优先级的调度算法:
嵌入式系统中断:
可重入函数和不可重入函数:
函数可重入是指一函数可以被多个任务调用,而不需要担心在任务切换的过程中,代码的执行会产生错误的结果。可重入函数任何时候都可以被中断,一段时间之后又可以运行,而相应的数据不会丢失。可重入函数或者只会使用局部变量,即变量保存在CPU寄存器中或堆栈中。如果使用全局变量,则要对全局变量予以保护。
eg:
void strcpy(char *dest,char *src) { while(*dest++ = *src++) { } *dest = NULL; }
函数Strcpy()做字符串复制。因为参数是存在堆栈中的,故函数Strcpy()可以被多个任务调用,而不必担心各任务调用函数期间会互相破坏对方的指针。
如果函数被多个任务调用,可能产生错误的结果,就是不可重入函数。
不可重入函数的例子,Swap()是一个简单函数,它使函数的两个形式变量的值互换。为便于讨论,假定使用的是可剥夺型内核,中断是开着的,Temp定义为整数全程变量。
eg:
int Temp; void swap(int *x ,int *y) { Temp = *x;//1 *x = *y;//2 *y =Temp;//3 }
把swap函数设置为任何函数可以调用,如果一个低优先级的任务正在执行swap()函数假设执行到
在第一个任务发生中断的时候全局变量这时候已经被赋值给了2,然后中断进入第二个任务第二个任务的函数当中因为也调用了swap函数,此时全局变量的Temp又被赋值为6,所以中断的第二个任务执行完的时候,程序又返回断点处继续执行,而此时的Temp值还是6与源程序所需要的数值发生错误,所以程序发生错误。
注意:
这只是一个简单的例子,如何能使代码具有可重入性一看就明白。然而有些情况下,问题并非那么易解。应用程序中的不可重入函数引起的错误很可能在测试时发现不了,直到产品到了现场问题才出现。如果在多任务上您还是把新手,使用不可重入型函数时,千万要当心。
如何解决避免这一问题?(以上边的swap函数为例)
- 把Temp定义为局部变量
- 调用Swap()函数之前关闭中断,调用之后在开启中断
- 用信号量禁止该函数在使用过程中在此被调用
基于优先级的调度算法:
·在多任务系统中,内核负责管理各个任务,或者换说每个任务分配CPU时间,并且负责任务之间的通讯。内核提供的基本服务时任务切换。之所以使用实时内核可以大大的简化应用系统的设计,是因为实时内核允许将应用分成若干个任务,由实时内核来管理他们。内核本身也增加了应用程序的额外负荷,代码空间增加ROM的用量,内核本身的数据结构增加RAM的用量,但更重要的是,每个任务都有自己的栈空间,这一块吃内存是相当厉害的因此,STN89C51,52等性能有限单片机一般不能运行实时内核,因为单片机的RAM很有限。但是例如STM32单片机通过UCOSIII提供必不可缺少的系统服务,诸如信号量管理、消息队列、延时等,使得CPU的利用更为有效。
可剥夺型内核:
因为系统响应时间很重要,所以μC/OS使用的是一种基于优先级的可剥夺型内核。最高优先级的任务一旦就绪,总能得到CPU的控制权。当一个运行着的任务使一个比它优先级高的任务进入了就绪态,当前任务的CPU使用权就被剥夺了,那个高优先级的任务立刻得到了CPU的控制权。如果是中断服务子程序使一个高优先级的任务进入就绪态,中断完成时,中断了的任务被挂起,优先级高的那个任务。使用可剥夺型内核,最高优先级的任务什么时候可以执行,可以得到CPU的控制权是可知的。使用可剥夺型内核使得任务级响应时间得以最优化。
使用可剥夺型内核时,应用程序不应直接使用不可重入型函数。调用**不可重入型函数**时,要满足互斥条件,这一点可以用互斥型信号量来实现。如果调用不可重入型函数时,低优先级的任务CPU的使用权被高优先级任务剥夺,不可重入型函数中的数据有可能被破坏。
在uC/OS中:
可以同时有64个就绪任务,每个任务都有各自的优先级。优先级用无符号整数来表示,从0到63,数字越大则优先级越低。 μC/OS总是调度就绪了的,优先级最高的任务获得CPU的控制权,不管这个任务是什么,执行什么样的功能,也不管该任务是否已经等了很久。
嵌入式系统中断:
嵌入式实时操作系统的中断是指在任务的执行过程中,当出现异常情况或特殊请求时,停止任务的执行,转而对这些异常情况或
特殊请求进行处理,处理结束后程序回到:
● 在前后台系统中,程序回到后台程序(前台:中断。后台:用户)
● 对不可剥夺型内核而言,程序回到被中断了的任务
● 对可剥夺型内核而言,让进入就绪态的优先级最高的任务开始运