第4章任务管理.docx
- 文档编号:7590474
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:31
- 大小:67.77KB
第4章任务管理.docx
《第4章任务管理.docx》由会员分享,可在线阅读,更多相关《第4章任务管理.docx(31页珍藏版)》请在冰豆网上搜索。
第4章任务管理
第4章任务管理1
4.0建立任务,OSTaskCreate()2
4.1建立任务,OSTaskCreateExt()6
4.2任务堆栈9
4.3堆栈检验,OSTaskStkChk()11
4.4删除任务,OSTaskDel()14
4.5请求删除任务,OSTaskDelReq()17
4.6改变任务的优先级,OSTaskChangePrio()20
4.7挂起任务,OSTaskSuspend()23
4.8恢复任务,OSTaskResume()25
4.9获得有关任务的信息,OSTaskQuery()26
第4章任务管理
在前面的章节中,笔者曾说过任务可以是一个无限的循环,也可以是在一次执行完毕后被删除掉。
这里要注意的是,任务代码并不是被真正的删除了,而只是µC/OS-Ⅱ不再理会该任务代码,所以该任务代码不会再运行。
任务看起来与任何C函数一样,具有一个返回类型和一个参数,只是它从不返回。
任务的返回类型必须被定义成void型。
在本章中所提到的函数可以在OS_TASK文件中找到。
如前所述,任务必须是以下两种结构之一:
voidYourTask(void*pdata)
{
for(;;){
/*用户代码*/
调用µC/OS-Ⅱ的服务例程之一:
OSMboxPend();
OSQPend();
OSSemPend();
OSTaskDel(OS_PRIO_SELF);
OSTaskSuspend(OS_PRIO_SELF);
OSTimeDly();
OSTimeDlyHMSM();
/*用户代码*/
}
}
或
voidYourTask(void*pdata)
{
/*用户代码*/
OSTaskDel(OS_PRIO_SELF);
}
本章所讲的内容包括如何在用户的应用程序中建立任务、删除任务、改变任务的优先级、挂起和恢复任务,以及获得有关任务的信息。
µC/OS-Ⅱ可以管理多达64个任务,并从中保留了四个最高优先级和四个最低优先级的任务供自己使用,所以用户可以使用的只有56个任务。
任务的优先级越高,反映优先级的值则越低。
在最新的µC/OS-Ⅱ版本中,任务的优先级数也可作为任务的标识符使用。
4.1建立任务,OSTaskCreate()
想让µC/OS-Ⅱ管理用户的任务,用户必须要先建立任务。
用户可以通过传递任务地址和其它参数到以下两个函数之一来建立任务:
OSTaskCreate()或OSTaskCreateExt()。
OSTaskCreate()与µC/OS是向下兼容的,OSTaskCreateExt()是OSTaskCreate()的扩展版本,提供了一些附加的功能。
用两个函数中的任何一个都可以建立任务。
任务可以在多任务调度开始前建立,也可以在其它任务的执行过程中被建立。
在开始多任务调度(即调用OSStart())前,用户必须建立至少一个任务。
任务不能由中断服务程序(ISR)来建立。
OSTaskCreate()的代码如程序清单L4.1所述。
从中可以知道,OSTaskCreate()需要四个参数:
task是任务代码的指针,pdata是当任务开始执行时传递给任务的参数的指针,ptos是分配给任务的堆栈的栈顶指针(参看4.02,任务堆栈),prio是分配给任务的优先级。
程序清单L4.1OSTaskCreate()
INT8UOSTaskCreate(void(*task)(void*pd),void*pdata,OS_STK*ptos,INT8Uprio)
{
void*psp;
INT8Uerr;
if(prio>OS_LOWEST_PRIO){
(1)
return(OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
if(OSTCBPrioTbl[prio]==(OS_TCB*)0){
(2)
OSTCBPrioTbl[prio]=(OS_TCB*)1;(3)
OS_EXIT_CRITICAL();(4)
psp=(void*)OSTaskStkInit(task,pdata,ptos,0);(5)
err=OSTCBInit(prio,psp,(void*)0,0,0,(void*)0,0);(6)
if(err==OS_NO_ERR){(7)
OS_ENTER_CRITICAL();
OSTaskCtr++;(8)
OSTaskCreateHook(OSTCBPrioTbl[prio]);(9)
OS_EXIT_CRITICAL();
if(OSRunning){(10)
OSSched();(11)
}
}else{
OS_ENTER_CRITICAL();
OSTCBPrioTbl[prio]=(OS_TCB*)0;(12)
OS_EXIT_CRITICAL();
}
return(err);
}else{
OS_EXIT_CRITICAL();
return(OS_PRIO_EXIST);
}
}
OSTaskCreate()一开始先检测分配给任务的优先级是否有效[L4.1
(1)]。
任务的优先级必须在0到OS_LOWEST_PRIO之间。
接着,OSTaskCreate()要确保在规定的优先级上还没有建立任务[L4.1
(2)]。
在使用µC/OS-Ⅱ时,每个任务都有特定的优先级。
如果某个优先级是空闲的,µC/OS-Ⅱ通过放置一个非空指针在OSTCBPrioTbl[]中来保留该优先级[L4.1(3)]。
这就使得OSTaskCreate()在设置任务数据结构的其他部分时能重新允许中断[L4.1(4)]。
然后,OSTaskCreate()调用OSTaskStkInit()[L4.1(5)],它负责建立任务的堆栈。
该函数是与处理器的硬件体系相关的函数,可以在OS_CPU_C.C文件中找到。
有关实现OSTaskStkInit()的细节可参看第8章——移植µC/OS-Ⅱ。
如果已经有人在你用的处理器上成功地移植了µC/OS-Ⅱ,而你又得到了他的代码,就不必考虑该函数的实现细节了。
OSTaskStkInit()函数返回新的堆栈栈顶(psp),并被保存在任务的0S_TCB中。
注意用户得将传递给OSTaskStkInit()函数的第四个参数opt置0,因为OSTaskCreate()与OSTaskCreateExt()不同,它不支持用户为任务的创建过程设置不同的选项,所以没有任何选项可以通过opt参数传递给OSTaskStkInit()。
µC/OS-Ⅱ支持的处理器的堆栈既可以从上(高地址)往下(低地址)递减也可以从下往上递增。
用户在调用OSTaskCreate()的时候必须知道堆栈是递增的还是递减的(参看所用处理器的OS_CPU.H中的OS_STACK_GROWTH),因为用户必须得把堆栈的栈顶传递给OSTaskCreate(),而栈顶可能是堆栈的最高地址(堆栈从上往下递减),也可能是最低地址(堆栈从下往上长)。
一旦OSTaskStkInit()函数完成了建立堆栈的任务,OSTaskCreate()就调用OSTCBInit()[L4.1(6)],从空闲的OS_TCB池中获得并初始化一个OS_TCB。
OSTCBInit()的代码如程序清单L4.2所示,它存在于0S_CORE.C文件中而不是OS_TASK.C文件中。
OSTCBInit()函数首先从OS_TCB缓冲池中获得一个OS_TCB[L4.2
(1)],如果OS_TCB池中有空闲的OS_TCB[L4.2
(2)],它就被初始化[L4.2(3)]。
注意一旦OS_TCB被分配,该任务的创建者就已经完全拥有它了,即使这时内核又创建了其它的任务,这些新任务也不可能对已分配的OS_TCB作任何操作,所以OSTCBInit()在这时就可以允许中断,并继续初始化OS_TCB的数据单元。
程序清单L4.2OSTCBInit()
INT8UOSTCBInit(INT8Uprio,OS_STK*ptos,OS_STK*pbos,INT16Uid,
INT16Ustk_size,void*pext,INT16Uopt)
{
OS_TCB*ptcb;
OS_ENTER_CRITICAL();
ptcb=OSTCBFreeList;
(1)
if(ptcb!
=(OS_TCB*)0){
(2)
OSTCBFreeList=ptcb->OSTCBNext;
OS_EXIT_CRITICAL();
ptcb->OSTCBStkPtr=ptos;(3)
ptcb->OSTCBPrio=(INT8U)prio;
ptcb->OSTCBStat=OS_STAT_RDY;
ptcb->OSTCBDly=0;
#ifOS_TASK_CREATE_EXT_EN
ptcb->OSTCBExtPtr=pext;
ptcb->OSTCBStkSize=stk_size;
ptcb->OSTCBStkBottom=pbos;
ptcb->OSTCBOpt=opt;
ptcb->OSTCBId=id;
#else
pext=pext;
stk_size=stk_size;
pbos=pbos;
opt=opt;
id=id;
#endif
#ifOS_TASK_DEL_EN
ptcb->OSTCBDelReq=OS_NO_ERR;
#endif
ptcb->OSTCBY=prio>>3;
ptcb->OSTCBBitY=OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX=prio&0x07;
ptcb->OSTCBBitX=OSMapTbl[ptcb->OSTCBX];
#ifOS_MBOX_EN||(OS_Q_EN&&(OS_MAX_QS>=2))||OS_SEM_EN
ptcb->OSTCBEventPtr=(OS_EVENT*)0;
#endif
#ifOS_MBOX_EN||(OS_Q_EN&&(OS_MAX_QS>=2))
ptcb->OSTCBMsg=(void*)0;
#endif
OS_ENTER_CRITICAL();(4)
OSTCBPrioTbl[prio]=ptcb;(5)
ptcb->OSTCBNext=OSTCBList;
ptcb->OSTCBPrev=(OS_TCB*)0;
if(OSTCBList!
=(OS_TCB*)0){
OSTCBList->OSTCBPrev=ptcb;
}
OSTCBList=ptcb;
OSRdyGrp|=ptcb->OSTCBBitY;(6)
OSRdyTbl[ptcb->OSTCBY]|=ptcb->OSTCBBitX;
OS_EXIT_CRITICAL();
return(OS_NO_ERR);(7)
}else{
OS_EXIT_CRITICAL();
return(OS_NO_MORE_TCB);
}
}
当OSTCBInit()需要将OS_TCB插入到已建立任务的OS_TCB的双向链表中时[L4.2(5)],它就禁止中断[L4.2(4)]。
该双向链表开始于OSTCBList,而一个新任务的OS_TCB常常被插入到链表的表头。
最后,该任务处于就绪状态[L4.2(6)],并且OSTCBInit()向它的调用者[OSTaskCreate()]返回一个代码表明OS_TCB已经被分配和初始化了[L4.2(7)]。
现在,我可以继续讨论OSTaskCreate()(程序清单L4.1)函数了。
从OSTCBInit()返回后,OSTaskCreate()要检验返回代码[L4.1(7)],如果成功,就增加OSTaskCtr[L4.1(8)],OSTaskCtr用于保存产生的任务数目。
如果OSTCBInit()返回失败,就置OSTCBPrioTbl[prio]的入口为0[L4.1(12)]以放弃该任务的优先级。
然后,OSTaskCreate()调用OSTaskCreateHook()[L4.1(9)],OSTaskCreateHook()是用户自己定义的函数,用来扩展OSTaskCreate()的功能。
例如,用户可以通过OSTaskCreateHook()函数来初始化和存储浮点寄存器、MMU寄存器的内容,或者其它与任务相关的内容。
一般情况下,用户可以在内存中存储一些针对用户的应用程序的附加信息。
OSTaskCreateHook()既可以在OS_CPU_C.C中定义(如果OS_CPU_HOOKS_EN置1),也可以在其它地方定义。
注意,OSTaskCreate()在调用OSTaskCreateHook()时,中断是关掉的,所以用户应该使OSTaskCreateHook()函数中的代码尽量简化,因为这将直接影响中断的响应时间。
OSTaskCreateHook()在被调用时会收到指向任务被建立时的OS_TCB的指针。
这意味着该函数可以访问OS_TCB数据结构中的所有成员。
如果OSTaskCreate()函数是在某个任务的执行过程中被调用(即OSRunning置为True[L4.1(10)]),则任务调度函数会被调用[L4.1(11)]来判断是否新建立的任务比原来的任务有更高的优先级。
如果新任务的优先级更高,内核会进行一次从旧任务到新任务的任务切换。
如果在多任务调度开始之前(即用户还没有调用OSStart()),新任务就已经建立了,则任务调度函数不会被调用。
4.2建立任务,OSTaskCreateExt()
用OSTaskCreateExt()函数来建立任务会更加灵活,但会增加一些额外的开销。
OSTaskCreateExt()函数的代码如程序清单L4.3所示。
我们可以看到OSTaskCreateExt()需要九个参数!
前四个参数(task,pdata,ptos和prio)与OSTaskCreate()的四个参数完全相同,连先后顺序都一样。
这样做的目的是为了使用户能够更容易地将用户的程序从OSTaskCreate()移植到OSTaskCreateExt()上去。
id参数为要建立的任务创建一个特殊的标识符。
该参数在µC/OS以后的升级版本中可能会用到,但在µC/OS-Ⅱ中还未使用。
这个标识符可以扩展µC/OS-Ⅱ功能,使它可以执行的任务数超过目前的64个。
但在这里,用户只要简单地将任务的id设置成与任务的优先级一样的值就可以了。
pbos是指向任务的堆栈栈底的指针,用于堆栈的检验。
stk_size用于指定堆栈成员数目的容量。
也就是说,如果堆栈的入口宽度为4字节宽,那么stk_size为10000是指堆栈有40000个字节。
该参数与pbos一样,也用于堆栈的检验。
pext是指向用户附加的数据域的指针,用来扩展任务的OS_TCB。
例如,用户可以为每个任务增加一个名字(参看实例3),或是在任务切换过程中将浮点寄存器的内容储存到这个附加数据域中,等等。
opt用于设定OSTaskCreateExt()的选项,指定是否允许堆栈检验,是否将堆栈清零,任务是否要进行浮点操作等等。
µCOS_Ⅱ.H文件中有一个所有可能选项(OS_TASK_OPT_STK_CHK,OS_TASK_OPT_STK_CLR和OS_TASK_OPT_SAVE_FP)的常数表。
每个选项占有opt的一位,并通过该位的置位来选定(用户在使用时只需要将以上OS_TASK_OPT_?
?
?
选项常数进行位或(OR)操作就可以了)。
程序清单L4.3OSTaskCreateExt()
INT8UOSTaskCreateExt(void(*task)(void*pd),
void*pdata,
OS_STK*ptos,
INT8Uprio,
INT16Uid,
OS_STK*pbos,
INT32Ustk_size,
void*pext,
INT16Uopt)
{
void*psp;
INT8Uerr;
INT16Ui;
OS_STK*pfill;
if(prio>OS_LOWEST_PRIO){
(1)
return(OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
if(OSTCBPrioTbl[prio]==(OS_TCB*)0){
(2)
OSTCBPrioTbl[prio]=(OS_TCB*)1;(3)
OS_EXIT_CRITICAL();(4)
if(opt&OS_TASK_OPT_STK_CHK){(5)
if(opt&OS_TASK_OPT_STK_CLR){
Pfill=pbos;
for(i=0;i #ifOS_STK_GROWTH==1 *pfill++=(OS_STK)0; #else *pfill--=(OS_STK)0; #endif } } } psp=(void*)OSTaskStkInit(task,pdata,ptos,opt);(6) err=OSTCBInit(prio,psp,pbos,id,stk_size,pext,opt);(7) if(err==OS_NO_ERR){(8) OS_ENTER_CRITICAL; OSTaskCtr++;(9) OSTaskCreateHook(OSTCBPrioTbl[prio]);(10) OS_EXIT_CRITICAL(); if(OSRunning){(11) OSSched();(12) } }else{ OS_ENTER_CRITICAL(); OSTCBPrioTbl[prio]=(OS_TCB*)0;(13) OS_EXIT_CRITICAL(); } return(err); }else{ OS_EXIT_CRITICAL(); return(OS_PRIO_EXIST); } } OSTaskCreateExt()一开始先检测分配给任务的优先级是否有效[L4.3 (1)]。 任务的优先级必须在0到OS_LOWEST_PRIO之间。 接着,OSTaskCreateExt()要确保在规定的优先级上还没有建立任务[L4.3 (2)]。 在使用µC/OS-Ⅱ时,每个任务都有特定的优先级。 如果某个优先级是空闲的,µC/OS-Ⅱ通过放置一个非空指针在OSTCBPrioTbl[]中来保留该优先级[L4.3(3)]。 这就使得OSTaskCreateExt()在设置任务数据结构的其他部分时能重新允许中断[L4.3(4)]。 为了对任务的堆栈进行检验[参看4.03,堆栈检验,OSTaskStkChk()],用户必须在opt参数中设置OS_TASK_OPT_STK_CHK标志。 堆栈检验还要求在任务建立时堆栈的存储内容都是0(即堆栈已被清零)。 为了在任务建立的时候将堆栈清零,需要在opt参数中设置OS_TASK_OPT_STK_CLR。 当以上两个标志都被设置好后,OSTaskCreateExt()才能将堆栈清零[L4.3(5)]。 接着,OSTaskCreateExt()调用OSTaskStkInit()[L4.3(6)],它负责建立任务的堆栈。 该函数是与处理器的硬件体系相关的函数,可以在OS_CPU_C.C文件中找到。 有关实现OSTaskStkInit()的细节可参看第八章——移植µC/OS-Ⅱ。 如果已经有人在你用的处理器上成功地移植了µC/OS-Ⅱ,而你又得到了他的代码,就不必考虑该函数的实现细节了。 OSTaskStkInit()函数返回新的堆栈栈顶(psp),并被保存在任务的0S_TCB中。 µC/OS-Ⅱ支持的处理器的堆栈既可以从上(高地址)往下(低地址)递减也可以从下往上递增(参看4.02,任务堆栈)。 用户在调用OSTaskCreateExt()的时候必须知道堆栈是递增的还是递减的(参看用户所用处理器的OS_CPU.H中的OS_STACK_GROWTH),因为用户必须得把堆栈的栈顶传递给OSTaskCreateExt(),而栈顶可能是堆栈的最低地址(当OS_STK_GROWTH为0时),也可能是最高地址(当OS_STK_GROWTH为1时)。 一旦OSTaskStkInit()函数完成了建立堆栈的任务,OSTaskCreateExt()就调用OSTCBInit()[L4.3(7)],从空闲的OS_TCB缓冲池中获得并初始化一个OS_TCB。 OSTCBInit()的代码在OSTaskCreate()中曾描述过(参看4.00节),从OSTCBInit()返回后,OSTaskCreateExt()要检验返回代码[L4.3(8)],如果成功,就增加OSTaskCtr[L4.3(9)],OSTaskCtr用于保存产生的任务数目。 如果OSTCBInit()返回失败,就置OSTCBPrioTbl[prio]的入口为0[L4.3(13)]以放弃对该任务优先级的占用。 然后,OSTaskCreateExt()调用OSTaskCreateHook()[L4.3(10)],OSTaskCreateHook()是用户自己定义的函数,用来扩展OSTaskCreateExt()的功能。 OSTaskCreateHook()可以在OS_CPU_C.C中定义(如果OS_CPU_HOOKS_EN置1),也可以在其它地方定义(如果OS_CPU_HOOKS_EN置0)。 注意,OSTaskCreateExt()在调用OSTaskCreateHook()时,中断是关掉的,所以用户应该使OSTaskCreateHook()函数中的代码尽量简化,因为这将直接影响中断的响应时间。 OSTaskCreateHook()被调用时会收到指向任务被建立时的OS_TCB的指针。 这意味着该函数可以访问OS_TCB数据结构中的所有成员。 如果OSTaskCreateExt()函数是在某个任务的执行过程中被调用的(即OSRunning置为True[L4.3(11)]),以任务调度函数会被调用[L4.3(12)]来判断是否新建立的任务比原来的任务有更高的优先级。 如果新任务的优先级更高,内核会进行一次从旧任务到新任务的任务切换。 如果在多任务调度开始之前(即用户还没有调用OSStart()),新任务就已经建立了,则任务调度函数不会被调用。 4.3任务堆栈 每个任务都有自己的堆栈空间。 堆栈必须声明为OS_STK类型,并且由连续的内存空间组成。 用户可以静态分配堆栈空间(在编译的时候分配)也可以动态地分配堆栈空间(在运行的时候分
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 任务 管理