2.配置调度算法
2.2
不带时间片的抢占式调度
配置如下时,调度算法就会变成不带时间片的抢占式调度
configUSE_PREEMPTION 1
configUSE_TIME_SLICING 0
和前面的唯一区别就是相同优先级的任务之间不会随时间自动切换。
如果不使用时间片,那么调度程序只会在发生这两种情况时,进行任务切换:
1
优先级更高的任务进入“就绪”态。
2
运行态任务变为阻塞态或被挂起。
很显然,不使用时间片时,任务切换的情况会变少,所以关闭时间切片可以减少调度器的处理开销。但是关闭时间切片也可能导致具有相同优先级的任务获得的处理时间相差很大。因此,一定要慎重使用。
task1为最高优先级的事件驱动任务,task2和Idle task有相同的优先级。但是由于关闭了时间片,任务切换只会在空闲任务阻塞或者挂起或者task1抢占后发生,所以空闲任务和task2虽然优先级相同,但是明显空闲任务占有的时间长很多。
2.3
协同调度
configUSE_PREEMPTION 0
configUSE_TIME_SLICING 随便
当使用协同调度时,只有当运行态任务进入阻塞态,或者运行态任务通过调用taskYIELD()主动让出,才会发生任务切换。
任务永远不会被抢占,不能使用时间片,时间片配置的值随便,无所谓。
task1、2、3优先级依次变低,刚开始task3运行,虽然task1和2优先级高,并且没有阻塞,但是也无法抢占,task3调用taskYIELD(),主动让出,因为task1优先级比task2高,task1就运行了,task1运行够了进入阻塞态,由于task2比task3优先级高,task2就运行了。
2.4
优缺点
多任务访问问题
在多任务程序中,应用程序编写人员必须注意一个资源不能被多个任务同时访问,因为同时访问可能会破坏资源。例如,考虑以下场景,其中正在访问的资源是UART(串口)。两个任务是向UART写入字符串,任务1写“abcdefghijklmnop”,任务2写“123456789”:
1
Task 1处于运行态,开始写它的字符串。它将“abcdefg”写入UART,然后离开运行态。
2
Task 2进入运行态,并在离开运行态之前向UART写入“123456789”。
3
任务1重新进入运行态,并将其字符串的剩余字符写入UART。
在该场景中,实际写入UART的内容是“abcdefg123456789hijklmnop”。Task 1写入的字符串没有按照预期的连续顺序写入UART,而是被损坏了,因为Task 2写入UART的字符串出现在UART中。
通常,使用协同调度比使用抢占调度更容易避免同时访问引起的问题。
当使用抢占式调度时,运行状态任务可以在任何时候被抢占,包括当它与另一个任务共享的资源处于不一致状态时。正如刚才UART示例所演示的,让资源处于不一致的状态可能导致数据损坏。
当使用协同调度时,应用程序编写人员控制何时可以切换到另一个任务(干完想干的再阻塞,或者让出)。因此,应用程序编写人员可以确保在资源处于不一致状态时不会发生切换到另一个任务的情况。在上面的UART示例中,应用程序编写人员可以确保Task 1在将其整个字符串写入UART之前不会离开运行态,这样做可以消除字符串被另一个任务的激活破坏的可能性。
很明显,协同调度比抢占调度响应要慢。
当使用协同调度时,最高优先级任务进入就绪态时并不一定会立即执行,必须等到运行态任务进入阻塞态或调用taskYIELD()才会被执行。
使用抢占调度时,当一个比运行态任务优先级更高的任务进入就绪态时,这个任务会立即执行。这一点对于必须在一定时间内响应高优先级任务的实时系统是非常重要的。至于多任务访问问题(其实也就是操作系统中的多线程问题),有其他手段去解决。
在RZ/T2L上做的实验
如果两个参数设置为:configUSE_PREEMPTION =0,configUSE_TIME_SLICING= 0或者1(随便) 称之为协同调度,当使用协同调度时,只有当运行态任务进入阻塞态,或者运行态任务通过调用taskYIELD()主动让出,才会发生任务切换。
任务永远不会被抢占,不能使用时间片,时间片配置的值随便。我做了一个实验截图如下:
上面的实验说明 “只有当运行态任务进入阻塞态,或者运行态任务通过调用taskYIELD()主动让出,才会发生任务切换”,此时与时间片1 ms已经没有什么关系了。
如果两个参数设置为 configUSE_PREEMPTION =1,configUSE_TIME_SLICING=1, 此时只有两个任务并且优先级相同,每个任务都持续做一件事情就会出现时间征为1ms的轮转情况:
通过上面的两个实验可以说明,时间片存的意义是相同优先级并且持续时间较长的处理任务,需要平等分享CPU使用权。但是如果一旦有一方主动放弃CPU或者阻塞或者更高优先级任务来了,调度器是不会等待一个时间片完全结束,再去调度就绪列表中的任务的,而是直接调用就绪列表里的第一个任务。这样的设计我认为是合理的,如果一定要等待时间片结束,是存在严重的资源浪费的。
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !