前言
“多年以后,经验老道的工程师面对着电脑中的各种或简单或复杂的系统,他将会回想起那个第一次接触RTOS系统的下午”。
上面玩了一个名句梗,回到正题,一个初出茅庐的嵌入式开发者总是会在做开发的路上遇到RTOS操作系统,RTOS(Real-time operating system)意为实时操作系统,在之前的开发过程中,我使用过UCOSIII和RTThread,其中RTT只是简单玩了一下,所以下面会围绕UCOSIII的讲下有关调度的知识和自己的应用理解。
由于个人使用的经验也不算特别深入,所以浅说一下app层的一些东西和一些抽象出的基本调度逻辑。(如果有错误的地方欢迎指正)
UCOS的核心:调度机制
调度机可以说是一个RTOS系统的灵魂所在,下面以适配STM32的UCOS文件组成为例(如图)
线程任务级调度
在UCOSIII最核心的文件UCOSIII-CPU中,我们可以在cpu_core.c中发现一个函数
在其函数描述中可以看到这样一段:“是否有新的,高优先级的任务将要运行”。阅读程序后我们得知,这是UCOSIII的任务级调度函数。其中这一句:
OSPrioHighRdy = OS_PrioGetHighest(); /* Find the highest priority ready */
即为获取任务最高优先级的线程并返回值的操作函数。
根据我们在操作系统中所学到的知识,可以知道,此函数的作用就是操作系统中描述的RTOS经典操作:获取就绪列表中的排在首位的最高优先级线程,并执行。
中断级调度
同样在cpu_core.c中,我们能够找到函数OSIntExit(void)
其开头描述是:这个函数被用于通知UCOS已完成了中断服务程序,当最后一个中断完成后,UCOS将告知调度机决定线程的调度。
除此之外,在UCOSIII中还有时间片轮转调度算法,此算法根据设置的时间片大小进行时间片节点处的线程调度。
怎样正确使用UCOSIII中的任务调度
我们已经简单了解了什么是UCOS中的调度(what),但是应该怎样使用呢?(how)。首先,我们已经得知,调度是基于优先级,中断,时间片的一个综合问题,需要设置好这些量以使RTOS系统更加正确高效的规划我们的任务的运行,并且需要注意程序的设计以避免一些经典的死锁问题。
优先级设置
每个RTOS系统中的任务都有优先级,一般来说UCOSIII设置为32个优先级,可以自主设置更多(其中最高优先级0和最低优先级31被UCOSIII本身使用)
它们在线程控制块中的设置如下
在这里我们采用了一种常规写法,创建一个start_task来进一步创建其他线程。与此同时,我们还创立了一个菜单显示函数menu_task来显示这个系统的一些信息。
这时我们来设计它们的优先级,由于start_task需要创建其他线程,所以它需要优于其他线程(必须此线程先跑完,其他线程才能顺利创建),这里我们将它的优先级设置为3,所以其他线程的优先级需低于3。
然后我们进行一波敏锐的需求分析,得知菜单显示函数menu_task是直接被使用者感知的一个任务,它运行的快速与否将会直接影响我们的操作体验,于是我们将它的优先级设置为4,一个仅次于start_task的优先级程度。
这里只是举了一个简单的例子,实际使用时对优先级的设置还需要具体情况具体分析。
时间片设置与中断程序编写
时间片的开启与大小需要设置一个宏定义和函数参数:
#if OS_CFG_SCHED_ROUND_ROBIN_EN //使能时间片轮转 //长度为1个系统时钟节拍 OSSchedRoundRobinCfg(DEF_ENABLED,1,&err); #endif
在os_cfg.h中打开OS_CFG_SCHED_ROUND_ROBIN_EN后即可进行时间片调度,这里我们设置时间片为一个系统时钟节拍,如果节拍长度为5ms,则时间片大小为1*5=5ms。
对于中断来说,需要注意的地方和普通程序编写时是一样的,如中断内处理时间不宜过长,不可在中断内进行睡眠等。
避免死锁
在操作系统的基础学习中,我们知道线程的调度可以基于不同的规则如FCFS(先来先服务)SJF(短作业优先)。UCOSIII中使用了优先级算法和时间片轮转的复合调度机制。
在这种机制下,我们需要避免常见的一些可能发生死锁的程序编写方式,这里举几个例子:
1.一个信号量资源被两个(或更多)线程需要,并且拿不到信号量资源会进入阻塞态,同时线程又占据了对方所需要的资源。这是一个经典的竞争问题,会导致某几个线程互相无法拿到资源而进入死锁。需要设计分配资源时避免。
2.优先级高的线程多,导致某一个低优先级线程在过长时间内无法运行,通常CPU资源足够时不会出现此问题,当出现时需要善于使用定时和重设优先级方法解决问题或直接提高优先级分布。
3.比较常见的一个问题:某个函数中包含了一个可能会进入while(1)情况的语句(可能由信号丢失,进入error提示等情况引起),导致整个系统停止运行。需要加入处理时间超时即跳过的判断语句来提高鲁棒性。
总得来说,无论是UCOS,还是RTT,其调度基本逻辑都是大差不差的,当然,想要使各个任务顺利的在系统中调度运行,所需要做的工作一定比上面提到的多得多——即使是对于轻量级的RTOS系统来说。
少部分例子参考了网络,文章仅作为学习交流用,转载注明出处即可。
标签:UCOSIII,优先级,知识,RTOS,调度,线程,设置 From: https://www.cnblogs.com/walker-at/p/17040783.html