一、任务的状态
任务的5种状态:休眠态、就绪态、运行态、挂起态(等待某一事件发生)和被中断态。
1、休眠态
任务驻留在内存中,但并不被多任务内核所调度。
2、就绪态
任务已经准备好,可以运行,但由于该任务的优先级比正在运行的任务的优先级低,暂时不能运行。
3、运行态
任务掌握了CPU的使用权,正在运行中。
4、挂起态
也叫等待事件态,指任务在等待某一事件的发生。例如:等待某外设的I/O操作,等待某共享资源由暂不能使用变成能使用状态,等待定时脉冲的到来,以结束目前的等待。
5、被中断态
发生中断时,CPU提供相应的中断服务,原来正在运行的任务暂不能运行。
二、任务的调度
任务级的调度是由函数OS_Sched()完成的。uC/OS-II任务调度的执行时间是常数,与应用程序建立了多少个任务没有关系。
1 void OS_Sched (void) 2 { 3 #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ 4 OS_CPU_SR cpu_sr; 5 #endif 6 INT8U y; 7 8 9 OS_ENTER_CRITICAL(); 10 if ((OSIntNesting == 0) && (OSLockNesting == 0)) { /* Sched. only if all ISRs done & not locked */ 11 y = OSUnMapTbl[OSRdyGrp]; /* Get pointer to HPT ready to run */ 12 OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); 13 if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */ 14 OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; 15 OSCtxSwCtr++; /* Increment context switch counter */ 16 OS_TASK_SW(); /* Perform a context switch */ 17 } 18 } 19 OS_EXIT_CRITICAL(); 20 }
(1)OS_Sched()检验这个优先级最高的任务是否是当前正在运行的任务,以避免不必要的任务调度。
(2)统计计数器OSCtxSwCtr的使用目的是让用户知道每秒做了多少次任务切换。
(3)调用OS_TASK_SW()宏,完成实际上的任务切换。
三、任务级的任务切换
任务切换代码须恢复该任务在CPU使用权被剥夺时保存下来的全部寄存器的值,以便让这个任务能继续运行。任务切换由2步完成:将被挂起任务的处理器寄存器推入堆栈,然后将较高优先级任务的寄存器值从栈中恢复到寄存器。OS_TASK_SW()挂起了正在执行的任务,而让CPU执行更重要的任务。
任务切换过程增加了应用程序的额外负荷,CPU的内部寄存器越多,额外负荷越重。任务切换所需时间取决于CPU有多少寄存器要入栈。
OS_TASK_SW()是宏调用,通常含有微处理器的软中断指令,因为uC/OS-II假定任务切换是靠软中断完成的。OS_TASK_SW()通常是汇编语言写的,因为C编译器不能从C语言中直接处理CPU寄存器。
四、给调度器上锁和开锁
(1)给调度器上锁函数OSSchedLock()用于禁止任务调度,直到任务完成之后,调用给调度器开锁函数OSSchedUnlock()为止。
(2)调用OSSchedLock()的任务,保持对CPU的使用权,尽管有个优先级更高的任务进入了就绪态。
(3) OSSchedLock()和OSSchedUnlock()必须成对使用。变量OSLockNesting跟踪OSSchedLock()函数被调用的次数。当OSLockNesting=0时,调度重新得到允许。
(4)如果多任务已经启动了(已经调用过OSStart()),则给调度器上锁和开锁才有意义。
(5)调用OSSchedLock()之后,应用程序不得调用可能会使当前任务挂起的系统功能函数,直到OSLockNesting=0为止。