优先级反转的实例
上节对一般意义上的优先级反转现象进行了描述,本节涉及的优先级反转则较上述更为复杂,更具有隐蔽性。本文采用的嵌入式微处理器为SAMSUNG公司的S3C2510, CPU核为arm940T。应项目要求任务task1和task2中分别进行调用微秒级和毫秒级的定时器功能函数,由于S3C2510处理器有5个32位定时器,因此只利用其中的两个即可。这里,ms级定时器实现的代码架构如下:
1) 中断处理函数:
LOCAL void Timer1_Int_Handle(void)
{
*S3C2510_TIC |= S3C2510_TIC_T1;/*清除中断*/
。
semGive(TelID4_Stop);/*释放二进制信号量*/
。
}
2) 毫秒级定时函数
void ms_Delay(int ms)
{
。
semTake(TelID4_Stop,WAIT_FOREVER);
。
}
3) 时钟初始化函数
void msTimer_Init()
{
TelID4_Stop=semCreate (SEM_Q_FI FO,SEM_EMPTY);/*初始化二进制信号量*/
assert(TelID4_Stop);
。
}
us级定时器功能实现的代码与上面类似,这里不再给出相应的代码。函数调用说明:先进行初始化,然后任务可随意调用定时功能函数。当某个任务调用定时功能函数时,该任务被信号量阻塞,同时定时器开始进行减一计数,当计数器减到0时,会产生一个中断请求信号,此时系统会调用中断处理函数,在中断处理函数时将信号量释放,此时信号量变的可用,任务继续执行。
当两个不同优先级任务task1,task2(设优先级分别为93和94)同时运行,并分别调用us和ms级定时功能函数时,优先级反转出现了,task1会被长时间阻塞。其中,task1和task2的调用如下:
void task1(void)
{
。
FOREVER
{
。
us_Delay();
。
taskDelay(4);
}
void Task2(void)
{
。
FOREVER
{
。
ms_Delay();
。
}
上述两个任务之间资源是独立的,但两个任务在一起运行时,高优先级任务task1在经过一段时间后会被长期阻塞。解决上述问题的方法比较简单,只要调整task1的任务优先级低于task2,这里选为95,则两个任务可长时间并行运行。
由于加入了中断和信号量,使系统任务调度变的复杂,从而导致两个原本看似独立的任务task1和task2,不能正常并行运行。造成此类现象的原因分析极其复杂,可视为是系统应用的一个盲点,但此类问题可通过总结规律而有效绕开。例如在上述问题中,若task1调用的定时函数的定时时间小于task2中的定时时间,则相应的任务优先级也应设有task1Priority《 task2Priority,这样高优先级任务就不会被阻塞。
结 语
本文结合实际例子,对VxWorks中优先级反转问题进行了探讨,并对此类问题的解决方法进行了描述。本文的探讨将使嵌入式系统开发人员更深入了解优先级反转问题。