嵌入式操作系统_第5章 ucOS-II - 任务就绪表及任务就绪组
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
多任务操作系统的核心工作就是任 务调度。
所谓调度,就是通过一个算法在多
μ的个作C的任依/函μ务OC数中/据任OS就确S__叫务就定III进做该I进就行是调运任及度行绪行任务器的调。表任任务度务的,务就思做想调这绪是项度表工
任务调度 “近似地每时每刻总是让优先级最高的
任任就务务就就绪绪绪任表表务和和任任处务务于就就运绪绪组组行的的状结登态构记、”注销。、为了保证 最这高优一先点级,就绪它任在务系的查统找或用户任务调用系统
OSTCBDly; //任务等待的时限(节拍数) OSTCBStat; //任务的当前状态标志 OSTCBPrio; //任务的优先级别
…… } OS_TCB;
当进行系统初始化时,初始化函 数会按用户提供的任务数为系统创建 具有相应数量的任务控制块并把它们 链接为一个链表。
由于这些任务控制块还没有对应 的任务,故这个链表叫做空任务块链 表。即相当于是一些空白的身份证。
while(i=0;i<8;i++){ if(OSRdyGrp%2!=0) break; else OSRdyGrp=OSRdyGrp/2;
}y=i; while(i=0;i<8;i++){
if(OSRdyTbl[y]%2!=0) break; else OSRdyTbl[y]=OSRdyTbl[y]/2; }x=i; prio=y*8+x;
0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1
1/0 1/0 1/0 1/百度文库 1/0 1/0 1/0 1/0 2
1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 3
1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 4
1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0
OSRdyGrp&=~OSMapTbl[prio>>3];
在就绪表中查找最高优先级任务
已经知道OSRdyGrp和OSRdyTbl 求优先级最高的任务的优先级,也就是先求 OSRdyGrp的从最低位找,第一个为1的位 置y;再求OSRdyTbl[y]的从最低位找,第 一个为1的位置x;prio=y*8+x; char OSRdyGrp,OSRdyTbl[8]; 如何编程实现?
因此任务切换OSCtxSw( )必定是一个中断 服务程序。
调度时机
对于实时系统来说,应该尽 可能地实现即时调度。
用函数OSTaskCreate( ) 创建任务
应用程序通过调用OSTaskCreate( ) 函数来创 建一个任务,OSTaskCreate( )函数的原型如下:
INT8U OSTaskCreate ( void (*task)(void *pd),//指向任务的指针 void *pdata, //传递给任务的参数 OS_STK *ptos, //指向任务堆栈栈顶的指针 INT8U prio //任务的优先级
嵌入式实时操作系统
μC/OS-II
信息学院
3.3任务控制块 (OS_TCB)
及其链表
μC/OS-II用来记录任务的堆
栈指针、任务的当前状态、任 务的优先级别等一些与任务管 理有关的属性的表就叫做任务 控制块
任务控制块就相当于是一个任 务的身份证,没有任务控制块 的任务是不能被系统承认和管 理的
任务控制块结构的主要成员
//output this tab for(n=0;n<=0xff;n++) {
if(n%0x10==0) printf("\n");
printf("%3d" , tab[n]); } printf("\n"); }
小结
系统通过查找任务就绪表来 获取待运行任务的优先级
优先级
任务切换过程
其实,调度 器在进行调 度时,在这 个位置还要 进行一下判 断:究竟是 待运行任务 是否为当前 任务,如果 是,则不切 换;如果不 是才切换, 而且还要保 存被中止任 务的运行环
任务控制块链表
空任务控制块链表
当应用程序调用函数OSTaskCreate( )创 建一个任务时,这个函数会调用系统函数 OSTCBInit ( )来为任务控制块进行初始 化。这个函数首先为被创建任务从空任务 控制块链表获取一个任务控制块,然后用 任务的属性对任务控制块各个成员进行赋 值,最后再把这个任务控制块链入到任务 控制块链表的头部
图5-6 在就绪表中查找最高优先级别任务的过程
从任务就绪表中获取优先级别最高的就绪任务可用如下 类似的代码:
y = OSUnMapTal[OSRdyGrp]; //D5、D4、D3位
x = OSUnMapTal[OSRdyTbl[y]]; //D2、D1、D0位
prio = (y<<3)+x;
//优先级别
任务就绪表就是一个二维数组OSRdyTbl[ ]
为加快访问任务就绪表的 速度,系统定义了一个变 量OSRdyGrp来表明就绪表 每行中是否存在就绪任务。
OSRdyGrp D7 D6 D5 D4 D3 D2 D1 D0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 x 7 6
OSRdyTbl[ ] 5 43 2 1 0
根据就绪表获得 获 待得 运待 行运 任行 务任 的务任 的 务任 控务 制控 块制 指块 针
处理器的SP=任 务块中保存的SP
恢复待运行任务 的运行环境
处理器的PC=任 务堆栈中的断点 地址
如何获得待运行 任务的任务控制
块?
任务切换宏 OS_TASK_SW( )
任务切换就是中止正在运行的任务 (当前任务),转而去运行另外一个 任务的操作,当然这个任务应该是就 绪任务中优先级别最高的那个任务
5 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0
6 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0
7 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 y
任务就绪表的示意图
D7 D6 D5 D4 D3 D2 D1 D0 prio=29 0 0 0 1 1 1 0 1
};
优先级判定表OSUnMapTbl[256]
OSUnMapTbl[]这个数组的生成原则:先 把一个数用二进制表示,然后从低位往高 位数,返回第一次碰到1的位置。比如: OSUnMapTbl[0x111100(60)] = 2。可 以看到,如果要表示8位数的对应关系, 则数组的大小为2^8=256。这也是为什么 OSRdyTbl[],OSRdyGrp采用8位的原因。
先保护被中 止任务的断
点数据
后恢复待运 行任务的断
点数据
不要企图用PUSH和POP指令来使程序计数 器PC压栈和出栈,因为没有这样的指令。
只好需一变次要通由中一宏断下或O了S_者。TA一SK次_S调W(用)来来使引发 中断动作和过OS程Ct调xS用w指( 令) 可以使PC压栈; 中断返回指令可以执使行P任C出务栈切。换工作
OSRdyGrp D7 D6 D5 D4 D3 D2 00 1 0 1 0
D1 D0 00
OSRdyTbl[y ] D7 D6 D5 D4
0110
D3 D2 00
D1 D0 00
y = OSUnMapTal[OSRdyGrp];
x= OSUnMapTal[OSRdyTbl[y]];
D7 D6 D5 D4 D3 D2 D1 D0 prio=29 0 0 0 1 1 1 0 1
OSRdyGrp | =OSMapTbl[prio>>3]; Y
X OSRdyTbl[prio>>3]
| = OSMapTbl[prio&0x07];
OSRdyGrp
OSRdyTbl[3 ]
D7 D6 D5 D4 D3 D2 D1 D0 D7 D6 D5 D4 D3 D2 D1 D0
1
1
把prio为29的任务置为就绪状态
再从代码生成的角度看看是如何得到这个 表的?
编程生成优先级判定表OSUnMapTbl[256]
#include <stdio.h> int main(void) {
int i,t,n; int tab[256]={0}; for(i=0;i<8;i++)
for(t=1;(t<<i)<256;t++) tab[t<<i]=i;
typedef struct os_tcb { OS_STK *OSTCBStkPtr; //指向任务堆栈栈顶的指针
…… struct os_tcb *OSTCBNext;//指向后一个任务控制块的指针 struct os_tcb *OSTCBPrev; //指向前一个任务控制块的指针
…… INT16U INT8U INT8U
函数及执行中断服务程序结束时总是调 用调度器,来确定应该运行的任务并运 行它 。
为了能够使系统清楚地知道,系统中 哪些任务已经就绪,哪些还没有就绪, μC/OS_II在RAM中设立了一个记录 表,系统中的每个任务都在这个表中 占据一个位置,并用这个位置的状态 (1或者0)来表示任务是否处于就绪 状态,这个表就叫做任务就绪状态表, 简称叫任务就绪表
3.4任务就绪表 及
任务调度
多任务操作系统的核心工作就是任务调 度。
所谓调度,就是通过一个算法在多个任 务中确定该运行的任务,做这项工作的函数 就叫做调度器。
μC/OS_II进行任务调度的思想是 “近 似地每时每刻总是让优先级最高的就绪任务 处于运行状态” 。为了保证这一点,它在 系统或用户任务调用系统函数及执行中断服 务程序结束时总是调用调度器,来确定应该 运行的任务并运行它 。
或
y = OSUnMapTbl[OSRdyGrp]; prio = (INT8U)((y << 3)
+ OSUnMapTbl[OSRdyTbl[y]]);
优先级判定表OSUnMapTbl[256] (os_core.c)
举例: 如OSRdyGrp的值为
00101000B,即0X28,则 查得 OSUnMapTbl[OSRdyGrp] 的值是3,它相应于 OSRdyGrp中的第3位置1;
如OSRdyTbl[3]的值是 11100100B,即0XE4,则 查 OSUnMapTbl[OSRdyTbl[ 3]]的值是2,则进入就绪态 的最高任务优先级
Prio=3*8+2=26
INT8U const OSUnMapTbl[] = { 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
在程序中,可以用类似下面的代码把优先 级别为prio的任务置为就绪状态:
OSRdyGrp | =OSMapTbl[prio>>3]; OSRdyTbl[prio>>3] | = OSMapTbl[prio&0x07];
如果要使一个优先级别为prio的任务脱离就绪 状态则可使用如下类似代码:
if((OSRdyTbl[prio>>3]&=~OSMapTbl[prio&0x07])== 0)