微型抢占式多任务实时内核设计
??对周期性定时器,每隔定时时长的时间,内核就调用的lpTimerFunc指向的函数,并且将timerId以消息的方式发送给任务,对任务的动态优先级的影响与普通消息一样。因此,要想取得实时性较好的定时器,只需将timerId设在0~15之间。与一次性定时相关的是睡眠函数和限时等待同步对象的函数。任务使用这两个函数而进入休眠态后,在定时时间到时,内核将其恢复为就绪态,并自动释放定时器资源。系统定时处理的核心代码如下:
if( !(--pTimer->elapse) ){ /*elapse减为零表示时间到*/
if( pTimer->lpTimerFunc)(*pTimer->lpTimerFunc)(pTimer->
taskId,pTimer->timerId);
switch( pTimer->timerId&0xF0 ){
case SLEEP_ID: /*一次性定时*/
os_slpState |= taskMask; /*结束休眠态*/
os_timerState |= timerMask; /*释放定时器*/
break;
case 0x00: /*发送紧急级定时器消息*/
pTCB->msg[0] |= os_maskTable[pTimer->timerId];
os_rdyhState |= os_maskTable[pTCB->priority ];;
break;
case 0x10: : /*发送普通级定时器消息*/
pTCB->msg[1] |= os_maskTable[pTimer->timerId&0x0f];
os_rdyState |= os_maskTable[pTCB->priority ];;
}
}
5 同 步
??抢占式多任务下,低优先级的任务可以被高优先级任务打断执行。以常规方式访问共享变量或资源时,会出现奇怪的结果。比如,一个任务调用printf(“12345”)试图在输出设备上输出“12345”,但执行中被高优先级任务打断;而高优先级任务也调用printf(“67890”)试图输出“67890”,最终的输出结果可能是“1267890345”之类。这就是多任务环境下的任务同步问题。
??同步方式有两种,一种为用户同步方式,不需要与内核打交道,具有速度快的优点,但只适合保护执行时间短的代码;另一种是内核同步方式,需要通过内核来实现,速度相对较慢,但可保护执行时间长的代码。
5.1 用户同步方式
??用户方式下的同步是通过关键代码段(critical section)保护来实现。关键代码段是指这样一小段代码,它执行时必须独占对某些共享资源的访问权,不允行被其它试图访问该资源的代码打断。最简单的是得用关/开中断来实现,优点是速度极快,缺点是带来中断延迟,只适合执行时间极短的代码段。另一简单的方案是通过加锁/解锁调度器来实现,即在关键代码段执行期间禁止内核进行任务切换。采用这种方法,不会带来中断延迟,但带来了调度延迟。在MicroStar中,对os_nLayers加1即可锁定调度器,减1即可解锁。但
《微型抢占式多任务实时内核设计(第5页)》