13.4.5 高优先级查找
1.函数vTaskSwitchContext()
PendSV中断服务程序调用函数vTaskSwitchContext()来获取下一个要运行的任务,也就是查找已经就绪的优先级最高的任务,函数主要源码如下。

主要语句功能如下。
①如果调度器挂起,那么就不能进行任务切换。
②查找高优先级函数,从就绪列表中查找优先级最高的优先级数值。
2.高优先级查找算法
在FreeRTOS中,查找下一个要运行的任务有两种方法:一种是软件实现法,另一种是硬件实现法。选择哪种方法是通过宏configUSE_PORT_OPTIMISED_TASK_SELECTION来决定的,当这个宏为1的时候,就使用硬件实现法,否则就使用软件实现法。
(1)软件实现法。
每一个任务均按优先级数值对应一个自己所属的任务列表,列表中的列表项代表任务,如果有列表项存在,表示任务就绪(运行态也存在),每一次任务就绪后都会进行比较,把最大的优先级数值存放在变量uxTopReadyPriori ty中,因此该变量中始终存放的是优先级最高的数值。
软件实现法的定义如下。

主要语句功能如下。
①pxReadyTasksLists[]为就绪任务列表数组,一个优先级对应一个列表,同优先级的就绪任务都挂到相应的列表中。uxTopReadyPriori ty代表处于就绪态的最高优先级数值,每次创建任务的时候,都会判断新任务的优先级数值是否大于uxTopReadyPriori ty,如果大于,就将这个新任务的优先级赋值给变量uxTopReadyPriori ty。函数prvAddTaskToReadyList()也会修改这个值,将某个任务添加到就绪列表中的时候都会用uxTopReadyPriori ty来记录就绪列表中的最高优先级。这里就从这个最高优先级开始判断,看看哪个列表不为空就说明哪个优先级有就绪的任务。函数listLIST_IS_EMPTY()用于判断某个列表是否为空,变量uxTopPriori ty用来记录这个有就绪任务的优先级。(https://www.daowen.com)
②找到了高优先级数值uxTopPriori ty,接下来就用函数listGET_OWNER_OF_NEXT_ENTRY()来获取pxReadyTasksLists[uxTopPriori ty]列表中的下一个列表项,列表项中的pvOwner就指向该任务的任务控制块。把任务控制块赋值给pxCurrentTCB,至此就确定了要运行的任务,开始任务调度。
(2)硬件实现法。
硬件实现法是利用某些CPU中的一些高级指令来加速查找高优先级任务的一种方法,如ARM Cortex-M3的指令集中,指令CLZ可实现高优先级数值查找,该指令功能是计算源操作数(二进制)前导零的个数。
硬件实现法的定义如下。

主要语句功能如下。
①portGET_HIGHEST_PRIORITY()函数获取处于就绪态的最高优先级。该宏定义如下。

例如,13.2.1小节应用案例中的3个任务的优先级分别为1、2和2,调用xTaskCreate()函数后,3个任务均就绪,就绪列表的全局变量uxTopReadyPriority=0x00000006。高优先级数据的查找方法如下。
第一步:CLZ(0x00000006)=29。0x00000006转换成32位二进制,最高位1前导0的个数为29个。
第二步:31-29=2,因此找到了高优先级数值2。
用这种方法查找高优先级数值是最快的,建议用户使用此方法。
②根据优先级数值找到列表,把任务控制块传给当前任务控制块pxCurrentTCB。