ucosii的任务状态转换图
ucosiii任务状态转换图
任哲的图
1、为了及时响应事件,我们用中断而不是轮询寄存器的标志的方式,来判断是否有外部事件发生
例如,为了判断按键是否按下,可以轮询GPIO输入数据寄存器,或者GPIO->EXTI->NVIC->ISR中断函数
2、为了及时处理事件,我们在中断里最多只是做简单的处理,复杂的处理需要中断给某个任务发一个信号,通知某个任务专门处理这个事件
退出中断时,就可能会从当前的任务,切换到一个处理按键事件的任务
中断退出时,可能返回原来的任务,也可能去运行优先级更高的按键任务来及时处理按键事件,所以ucosiii的图,更清楚地表明了这个概念:
无新高级任务则返回原任务:Interrupted->Running
有新高级任务则运行高级任务:Interrupted->Ready(等按键任务运行完了,本任务还有机会继续运行)
本篇博客,我也以ucoiii的图,来分析任务状态的转换。
任务转换时,影响TCB里的任务状态,也影响全局变量就绪表。
五个状态说明
节点(图上的圆圈) | 说明 |
Dormant冬眠态 | a task that resides in memory but has not been made available to µC/OS-III. Dormant-> :OSTaskCreate 操作系统可以调度rom里的task代码 ->Dormant :OSTaskDel 操作系统不能调度rom里的task代码 |
Ready 就绪态 | 一个任务一厢情愿地说自己准备好了;就绪表里很多任务都说自己准备好了。 pending->ready->running the newly readied task will run immediately if it is the most important task. 往往一个任务被就绪后,会立马进行一次调度,变成running态,因为按照实时的原则 一个高优先级的任务就绪后,我们希望能立马运行,如下面的两个例子中的任务2。 【中断级调度,被动让出cpu】OSTimeTick+OSIntExit OS_CPU_SysTickHandler->OSTimeTick: if (ptcb->OSTCBDly == 0u)某个任务延时到了,变成就绪状态 OSIntExit:退出滴答中断时,发现有就绪的高优先级任务,会切换过去 任务1(running到intrrrupted到ready)->任意位置发生定时器中断->切换到任务2(pending到ready到running) 【任务级切换,主动让出cpu】OSTaskResume+OS_TASK_SW: 任务1(running到ready)->在特定位置调用OSTaskResume->切换到任务2(pending到ready到running) |
running | The most important ready-to-run task is placed in the Running state. 所以一个任务说自己ready只是一厢情愿,你往往一点都不重要,你没有机会跟cpu在一起的。 任务变成运行有三种路径 1、初始化的时候,OSTaskCreate->OSStart 2、上面的,pending->ready->running(如果是在中断里被就绪,就是中断级切换到running;否则,任务级) 3、一个任务被中断后通常是返回的,那如果不返回也别灰心啊,等紧急的按键任务处理完了调用delay主动让出,你还有机会继续运行的。 running->intrrrupted->ready->running(下一次运行的机会哪里来呢,通常是等按键任务处理完了,调用OSTimeDly时,这时进行任务级切换) |
pending | 等什么: OSSemPend:等事件(信号、互斥信号、邮箱、队列) OSTaskSuspend:waits until another task calls OSTaskResume() to make the task ready-to-run. OSTimeDly:等时间 |
interrupted | ISR should simply notify a task that an event occurred and let the task process the event(中断使就绪) 按键中断里,通过post使按键任务就绪,退出中断时,切换到按键中断。 定时中断里,如果没有哪个任务到时间,退出中断时,只是简单地返回被中断的任务。 ISRs are only allowed to make “Post” calls 不能调用pend 任务里可以pend,可以post 互斥信号量有优先级反转的问题 中断里不能释放互斥信号量 The only post call not allowed to be made from an ISR is OSMutexPost() since mutexes, as will be addressed later, are assumed to be services that are only accessible at the task level. 互斥量在任务里使用,获得后,本任务成为最高优先级,赶紧用完,赶紧释放 |
状态转换说明
1、任务1切换到任务2,任务1的状态从一个节点迁移到另一个节点,同时任务2的状态也发生变化。所以两个任务的状态应该一起观察,才能弄清楚流程。
2、从一个合理的角度,枚举出所有可能的情况,比如从操作系统当前运行的任务的角度:
从没有任务,到运行第一个任务task1
从一个任务切换到另一个任务,task1(?->?)->task2(?->?) 这四个问号,怎么排列组合?
3、每种迁移,都应该从下列角度来描述:
【函数调用链】【任务状态】【就绪表】、【补充说明】【实时原则】等。
#define OS_STAT_RDY 0x00u /* Ready to run */
#define OS_STAT_SEM 0x01u /* Pending on semaphore */
#define OS_STAT_MBOX 0x02u /* Pending on mailbox */
#define OS_STAT_Q 0x04u /* Pending on queue */
#define OS_STAT_SUSPEND 0x08u /* Task is suspended */
#define OS_STAT_MUTEX 0x10u /* Pending on mutual exclusion semaphore */
#define OS_STAT_FLAG 0x20u /* Pending on event flag group */
#define OS_STAT_MULTI 0x80u /* Pending on multiple events */
#define OS_STAT_PEND_ANY (OS_STAT_SEM | OS_STAT_MBOX | OS_STAT_Q | OS_STAT_MUTEX | OS_STAT_FLAG)
状态转换 (图上的箭头) | 描述 |
初始化 task1(Dormant->Ready->Running) | 【实时原则】 系统初始化后,第一次运行的是最高优先级任务,正如字面义一样 StartHighRdy 【函数调用链】 OSTaskCreate->OS_TCBInit: 【任务状态】OS_STAT_RDY 【就绪表】就绪 OSStart->OSStartHighRdy->pendsv (没有保护上文,仅仅切换下文) 【任务状态】OS_STAT_RDY 【就绪表】就绪 【补充说明】 运行中的任务其实也是RDY且就绪表就绪的,OSTimeDly中只在就绪表取消就绪,OSTimeTick里定时到了在就绪表里再次就绪。 tcb里一直是RDY的状态。 |
task(Running->Interrupted->Running) | 【实时原则】 即使优先级最高的任务,我中断也是可以打断你的啊。 类似前台后系统:main->中断->main(main现场的保存和恢复) task在运行的时候 被滴答中断打断,没有任何任务延时到期 中断直接返回了 或者,其他中断里,做简单的处理 然后直接返回 【补充说明】 中断嵌套,导致任务堆栈溢出,程序崩溃,串口打印崩溃日志 内核的某个寄存器给出崩溃的原因 修改堆栈大小,重新编译运行 |
(没有进入Pending)通过系统调用/中断,让高优先级任务就绪,抢占自己 因为没有进入pending,等高优先级任务运行完且调用延时让出cpu后,还是会轮到自己的 轮询系统:顺序执行 ucosii:while循环拆分成多个任务后,每当高优先级任务就绪就立马去执行,以确保实时性。 | |
系统调用使task2就绪 task1(Running->Ready) task2(Pending->Ready->Running) 任哲例5-4 MyTask->OSSemPost 任务里可以Post 【系统调用处,主动让出cpu,ready】 | 【实时原则】(让别的任务就绪,但是自己没有进入Pending) 任务1在任务里(自己不需要等什么),使高优先级的任务2就绪后,任务2抢占任务1 OStimeDlyResume使等时间的就绪 OSSemPost 使等信号的就绪 OSTaskResume 使等另一个任务调用OSTaskResume的就绪 【函数调用链】 OSSemPost { OS_EventTaskRdy; 【任务状态】OS_STAT_RDY 【就绪表】就绪 OS_Sched->OS_TASK_SW task1任务级切换到task2 } |
中断使task2就绪 task1(Running->Interrupted->Ready) task2(Pending->Ready->Running) ISR should simply notify a task that an event occurred and let the task process the event 中断里可以Post 【非临界段的任意位置,被动让出cpu,ready】 | 【实时原则】(让别的任务就绪,但是自己没有进入Pending) 任务1在中断里(自己不需要等什么),使高优先级的任务2就绪后,任务2抢占任务1 OSTimeTick使等时间的就绪 按键中断+OStimeDlyResume/OSSemPost/OSTaskResume (中断里可以Post互斥量之外的事件,不能Pend) 【函数调用链】 滴答中断OS_CPU_SysTickHandler->OSTimeTick->OSIntExit ->OSIntCtxSw 按键中断 { OSIntEnter OSSemPost { OS_EventTaskRdy:OS_STAT_RDY+就绪 OS_Sched:不会发生任务级切换,因为OSIntNesting != 0u } OSIntExit->OSIntCtxSw:task1退出中断时,中断级切换到task2 } |
(进入Pending)通过系统调用进入Pending状态,主动把cpu让给剩余的优先级最高的任务 注意,此时没有新的高优先级任务就绪,task2本来就是就绪状态。 | |
系统调用主动让出 task1(Running->Pending) task2(Ready->Running) 【系统调用处,主动让出cpu,pending】 | 【实时原则】 为了防止高优先级任务独占cpu,必须要cpu让给优先级较低的任务去运行。(如果高优先级任务不主动让出,那么即使系统调用或中断使就绪,就绪的那个任务,优先级低也没法运行。) OSTimeDly 等时间 OSSemPend等信号 OSTaskSuspend等另一个任务调用OSTaskResume 【函数调用链】 OSSemPend { 【任务状态】OS_STAT_SEM OS_EventTaskWait 【就绪表】取消就绪 OS_Sched->OS_TASK_SW } OSTaskSuspend { 【任务状态】OS_STAT_SUSPEND 【就绪表】取消就绪 OS_Sched->OS_TASK_SW } OSTimeDly { 【任务状态】还是 OS_STAT_RDY OSTCBCur->OSTCBDly = ticks; 【就绪表】取消就绪 OS_Sched->OS_TASK_SW } 【补充说明】 任务OSTimeDly,滴答中断OSTimeTick里递减ticks,定时到了任务可以重新运行,这整个过程中,一直都是OS_STAT_RDY状态。 只是在就绪表里就绪和取消就绪。 |
从上表可以看出,三种就绪:初始化就绪,系统调用使就绪、中断使就绪
上表的两行系统调用,都是任务主动让出cpu,区别是OStimeDlyResume和OSSemPost后任务没有进入pending状态,OSTimeDly和OSSemPend进入pending状态。
系统调用主动让出,其实在等待系统调用使就绪和中断使就绪,或者说等中断或者任务给自己发就绪信号,让自己再次就绪和运行!!!!!!!!!!!!!!
即发信号的主体,可以是任务(我写好数据后,任务2你可以读了),可以是中断(来事件了,任务2你赶紧处理啊)。
系统调用和中断使就绪,都使得任务1被抢占,进入ready状态;任务2就绪后,经过调度运行。
When the event occurs, the task is placed back into the ready list and µC/OS-III decides whether the newly readied task is the most important ready-to-run task.(任务2被就绪后,常常会调度并运行) If this is the case, the currently running task will be preempted (placed back in the ready list)(任务1被抢占,进入ready) and the newly readied task is given control of the CPU. In other words, the newly readied task will run immediately if it is the most important task.(原则,新就绪的任务,优先级高,就抢占)
临界段(关中断没法通过pendsv切换到其他任务,也没法切换到中断)> 优先级高的中断(嵌套) > 优先级低的中断 (最高优先级的任务也可以被中断打断啊)> > 优先级高的任务(系统调用或中断使高优先级就绪,先运行高优先级,抢占) >优先级低的任务 | |
临界段 | 通常是访问多个任务都能访问的全局变量 不希望被中断或者任务打断 |
中断的嵌套 | 先响应优先级高的中断 |
中断打断任务 | 中断可以使程序及时响应外部的按键事件 |
任务的抢占 | task1运行得好好的,有人按下按键 按键中断:及时响应事件,给按键任务Post信号 按键任务:及时处理事件,Pend到信号后,立即处理 task1运行中的按键中断使高优先级的按键任务就绪 按键任务抢占task1是有道理的啊,可以及时在按键任务里处理按键事件 按下按键的响应时间: 1跳转到按键中断,发信号,很快的 2中断退出时,中断级调度切换到按键任务,很快的 |
我这个表格这么吊,不赞一下么。