背景任务的几种常见调度方式
我们喜欢RTOS,因为它足够简单;我们讨厌RTOS,因为它足够复杂。从“裸奔”到RTOS,首先意味着工程师们要去适应这些“新”东西,更要命的是要去给BOSS证明这些东西的可靠性——这是一个足够漫长的过程。在如今RTOS飞舞的时代,我们依然一路“裸奔”。呃,严重跑题了~~我不想说RTOS,我要说的是“裸奔”下的几种“风骚走位”——调度方式。
相对于RTOS,“裸奔”属于“前后台”框架。形象地说,后台就是那些在main()的超级循环里面的执行的函数集合;前台就是那些在ISR中执行的函数集合。其中,前台程序通常是对实时性能要求较为严格的任务,通常也是系统的核心任务。因此,后台程序就被称为“背景任务”。
下面讲讲几种背景任务的调度方式:
l 方式1——非周期连续执行
这种方式应该是任何MCU初学者都会用到的,如下:
遥想当年瞎捣鼓51单片机时,全身上下只知道写个main(),硬生生在里面写了个电子日历=。= 本着“尽快跑”的简单实惠原则,方式1实现了一个闭环,非常适合应用于那些足够低端的MCU。(当然也不要指望这种情况下跑大量的实时code)
l 方式2——周期执行
相对于方式1,方式2强调了执行的“周期”实现。意味着设计者希望这些代码可以按照固定周期执行。如下:
方式2应用场合更为广泛一些。需要注意的是:即使前台任务足够短小,也只有首个任务A是较为实时的,后续任务都要受到前一个任务的执行时间影响,从而变得更加不实时——这是固有的缺陷。还有,如果多个任务的周期存在倍数关系,那么将会造成CPU负荷不均衡——即“忙就忙死,闲就闲死”现象。
另外还可以看出这些背景任务的执行周期是相同的(假设各任务的执行时间固定),那么我们可以说这些任务具有统一的速率。但是,如果我们希望不同任务有不同的速率呢?请看方式3.
l 方式3——周期多速率执行
这里多速率,指的就是不同任务具有不同的执行周期。周期越短的任务通常是被认为优先级越高的任务。如下:
如上图所示,类似(A->B1->C1->D1)组成了一个小环,若干个这样的小环组成一个大环。
假设节拍timeout表示1ms,那么各任务的执行周期如下:
任务 |
执行周期 (ms) |
优先级 |
A |
1 |
最高 |
B1 |
2 |
高 |
B2 |
2 |
|
C1 |
3 |
中 |
C2 |
3 |
|
C3 |
3 |
|
D1 |
4 |
低 |
D2 |
4 |
|
D3 |
4 |
|
D4 |
4 |
对比方式2,方式3显然的一个好处就是可以实现CPU负荷相对均衡。但是可以看出,方式3同样存在方式2中所说缺陷:即使前台任务足够短小,也只有首个任务A是较为实时的,后续任务都要受到前一个任务的执行时间影响,从而变得更加不实时。
如何尽量确保背景任务的实时性:
作为背景任务,自然不能指望他们拥有与前台任务一样的实时性能。但是也总不能落后太多吧 >_<
下面的分析是基于前台任务的运行时间为常数。
(1)对于方式2,显然,只要在同一个环内,任务A~F的执行时间之和(包括前台任务占用的时间)小于timeout周期,即可相对保证背景任务的实时性能。
(2)对于方式3,只要在同一个小环内,任务A~D的执行时间之和(包括前台任务占用的时间)小于timeout周期,即可相对保证背景任务的实时性能。
结语
不管是跑RTOS还是“裸奔”,对系统的时序分析都是至关重要的,其分析深度往往体现了工程师对软件整体的把握程度。个人经验认为,“裸奔”足以应付大多数的单片机系统设计;至于RTOS嘛,要么就不用,要么就用最好的——包括人和产品。
用户1311192 2014-9-30 09:26