所谓优先级翻转问题(priority inversion)即当一个高优先级任务通过
信号量机制访问共享资源时,该信号量已被一低优先级任务占有,而这个低优先级任务在访问共享资源时可能又被其它一些中等优先级任务抢先,因此造成高优先级任务被许多具有较低优先级任务阻塞,实时性难以得到保证。
解决优先级翻转问题有优先级天花板(priority ceiling)和优先级继承(priority inheritance)两种办法。
优先级天花板是当任务申请某资源时, 把该任务的优先级提升到可访问这个资源的所有任务中的最高优先级, 这个优先级称为该资源的优先级天花板。这种方法简单易行, 不必进行复杂的判断, 不管任务是否阻塞了高优先级任务的运行, 只要任务访问共享资源都会提升任务的优先级。
优先级继承是当任务A 申请共享资源S 时, 如果S正在被任务C 使用,通过比较任务C 与自身的优先级,如发现任务C 的优先级小于自身的优先级, 则将任务C的优先级提升到自身的优先级, 任务C 释放资源S 后,再恢复任务C 的原优先级。这种方法只在占有资源的低优先级任务阻塞了高优先级任务时才动态的改变任务的优先级,如果过程较复杂, 则需要进行判断。
ucosII在使用互斥信号量的时候,使用了优先级继承功能,OSMutexPend和OSMutexPost两个函数必须在一个任务中成对使用。例如现在有ABC三个任务。优先级顺序为A>B>C
首先创建互斥量OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err),其中prio意思需要继承的优先级,尽量设定为最高值,假如设定为5.
1 当互斥量没有任务访问时候,A先去获取互斥量,C后获取信号量,A调用OSMutexPend
if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) //
{
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Yes, Acquire the resource */
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save priority of owning task */ //C就不能获取,因为上面的if条件不成立了。
pevent->OSEventPtr = (void *)OSTCBCur; /* Point to owning task's OS_TCB */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return; //A从这里返回
}
C在调用OSMutexPend时,因为if条件不成立,往下执行
pip = (INT8U)(pevent->OSEventCnt >> 8); /* No, Get PIP from mutex */
mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get priority of mutex owner */
ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */
if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) //OSTCBCur->OSTCBPrio指向C,而mprio指向A,所以此if不成立,不提升C的优先级到5,系统进行自动调度。当A调用OSMutexPost释放信号量的时候
if (OSTCBCur->OSTCBPrio == pip)//此if不成立,因为A没有进行优先级继承,直接将C设置为ready状态,然后调用系统调度,C开始执行。
2 当互斥量被C先于A调用,C得到资源后顺利返回,A没有获取资源,执行下面的程序,
pip = (INT8U)(pevent->OSEventCnt >> 8); /* No, Get PIP from mutex */
mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get priority of mutex owner */
ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */
if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) //OSTCBCur->OSTCBPrio指向A,而mprio指向C,此if成立,将C的优先级提示为5,B因此就不能执行了。
当c执行完后,调用OSMutexPost,下面的if条件满足,因此恢复C到原始的优先级
if (OSTCBCur->OSTCBPrio == pip) //pip一直是5,C也被提升为5,所以恢复C的优先级,释放资源后,A开始执行。
以上过程就防止了B先于A执行。
ucosII在使用互斥信号量的时候,使用了优先级继承功能,OSMutexPend和OSMutexPost两个函数必须在一个任务中成对使用。例如现在有ABC三个任务。优先级顺序为A>B>C
首先创建互斥量OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err),其中prio意思需要继承的优先级,尽量设定为最高值,假如设定为5.
1 当互斥量没有任务访问时候,A先去获取互斥量,C后获取信号量,A调用OSMutexPend
if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) //
{
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Yes, Acquire the resource */
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save priority of owning task */ //C就不能获取,因为上面的if条件不成立了。
pevent->OSEventPtr = (void *)OSTCBCur; /* Point to owning task's OS_TCB */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return; //A从这里返回
}
C在调用OSMutexPend时,因为if条件不成立,往下执行
pip = (INT8U)(pevent->OSEventCnt >> 8); /* No, Get PIP from mutex */
mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get priority of mutex owner */
ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */
if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) //OSTCBCur->OSTCBPrio指向C,而mprio指向A,所以此if不成立,不提升C的优先级到5,系统进行自动调度。当A调用OSMutexPost释放信号量的时候
if (OSTCBCur->OSTCBPrio == pip)//此if不成立,因为A没有进行优先级继承,直接将C设置为ready状态,然后调用系统调度,C开始执行。
2 当互斥量被C先于A调用,C得到资源后顺利返回,A没有获取资源,执行下面的程序,
pip = (INT8U)(pevent->OSEventCnt >> 8); /* No, Get PIP from mutex */
mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get priority of mutex owner */
ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */
if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) //OSTCBCur->OSTCBPrio指向A,而mprio指向C,此if成立,将C的优先级提示为5,B因此就不能执行了。
当c执行完后,调用OSMutexPost,下面的if条件满足,因此恢复C到原始的优先级
if (OSTCBCur->OSTCBPrio == pip) //pip一直是5,C也被提升为5,所以恢复C的优先级,释放资源后,A开始执行。
以上过程就防止了B先于A执行。