FreeRTOS 查找最高优先级的就绪任务源码分析

news2025/1/22 13:00:51

一、就绪任务列表

就绪列表 pxReadyTasksLists[ configMAX_PRIORITIES ] 是一个数组, 数组里面存的是就绪任务的 TCB(准确来说是 TCB 里面的 xStateListItem 节点) ,数组的下标对应任务的优先级,优先级越低对应的数组下标越小(即数字优先级越小,逻辑优先级也越小)。空闲任务的优先级最低,对应的是下标为 0 的链表。

pxReadyTasksLists就绪任务列表定义在tasks.c中:

PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */

configMAX_PRIORITIES 该宏定义在FreeRTOSConfig.h中,代表支持的最大优先级。我们看到configMAX_PRIORITIES 即为就绪任务列表的数组元素个数。那么我们实际可用的任务优先级只能是0到configMAX_PRIORITIES-1,因为pxReadyTasksLists的元素下标是0到configMAX_PRIORITIES-1。

通常在FreeRTOSConfig.h中对于软件定时器的优先级定义为(configMAX_PRIORITIES-1)即相当于最高优先级了。

#define configTIMER_TASK_PRIORITY		        (configMAX_PRIORITIES-1)        //软件定时器优先级

pxReadyTasksLists是List_t 类型的数组,看看List_t 是什么:


struct xLIST_ITEM
{
	configLIST_VOLATILE TickType_t xItemValue;			
	struct xLIST_ITEM * configLIST_VOLATILE pxNext;		
	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
	void * pvOwner;										
	void * configLIST_VOLATILE pvContainer;				
};
typedef struct xLIST_ITEM ListItem_t;	

struct xMINI_LIST_ITEM
{
	configLIST_VOLATILE TickType_t xItemValue;
	struct xLIST_ITEM * configLIST_VOLATILE pxNext;
	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

typedef struct xLIST
{
	configLIST_VOLATILE UBaseType_t uxNumberOfItems;
	ListItem_t * configLIST_VOLATILE pxIndex;			
	MiniListItem_t xListEnd;	
} List_t;

每个List_t元素可以看成链表,每个链表中指向的是当前处于就绪态的同一优先级的任务TCB
在这里插入图片描述

任务在创建的时候,会根据任务的优先级将任务插入到就绪列表不同的位置,相同优先级的任务插入到就绪列表里面的同一条链表中。

二、查找最高优先级的就绪任务方法

1、通用方法

从最高优先级对应的就绪列表数组下标开始寻找当前链表下是否有任务存在,如果没有,则 uxTopPriority 减一操作,继续寻找下一个优先级对应的链表中是否有任务存在,如果有则跳出 while 循环,表示找到了最高优先级的就绪任务。之所以可以采用从最高优先级往下搜索,是因为任务的优先级与就绪列表的下标是一一对应的,优先级越高,对应的就绪列表数组的下标越大。获取优先级最高的就绪任务的 TCB,然后更新到 pxCurrentTCB。

2、优化方法

Cortex-M 内核有一个计算前导零的指令CLZ。前导零就是计算一个变量(Cortex-M 内核单片机的变量为 32位)从高位开始第一次出现 1 的位的前面的零的个数。比如:一个 32 位的变量 uxTopReadyPriority,其位 0、位 24 和 位 25 均 置 1 , 其 余 位 为 0 。 那 么 使 用 前 导 零 指 令 __CLZ (uxTopReadyPriority)可以很快的计算出 uxTopReadyPriority 的前导零的个数为 6。利用前导零计算指令可以很快计算出就绪任务中的最高优先级。

三、源代码分析

两种查找最高优先级的就绪任务方法定义在task.c文件中。

#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )

	#define taskRECORD_READY_PRIORITY( uxPriority )														\
	{																									\
		if( ( uxPriority ) > uxTopReadyPriority )														\
		{																								\
			uxTopReadyPriority = ( uxPriority );														\
		}																								\
	} 

	/*-----------------------------------------------------------*/

	#define taskSELECT_HIGHEST_PRIORITY_TASK()															\
	{																									\
	UBaseType_t uxTopPriority = uxTopReadyPriority;														\
																										\
		/* Find the highest priority queue that contains ready tasks. */								\
		while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) )							\
		{																								\
			configASSERT( uxTopPriority );																\
			--uxTopPriority;																			\
		}																								\
																										\
		/* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of						\
		the	same priority get an equal share of the processor time. */									\
		listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );			\
		uxTopReadyPriority = uxTopPriority;																\
	} /* taskSELECT_HIGHEST_PRIORITY_TASK */

	/*-----------------------------------------------------------*/
	#define taskRESET_READY_PRIORITY( uxPriority )
	#define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )

#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */

	/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is
	performed in a way that is tailored to the particular microcontroller
	architecture being used. */

	/* A port optimised version is provided.  Call the port defined macros. */
	#define taskRECORD_READY_PRIORITY( uxPriority )	portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )

	/*-----------------------------------------------------------*/

	#define taskSELECT_HIGHEST_PRIORITY_TASK()														\
	{																								\
	UBaseType_t uxTopPriority;																		\
																									\
		/* Find the highest priority list that contains ready tasks. */								\
		portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );								\
		configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 );		\
		listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );		\
	} /* taskSELECT_HIGHEST_PRIORITY_TASK() */

	/*-----------------------------------------------------------*/
	#define taskRESET_READY_PRIORITY( uxPriority )														\
	{																									\
		if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 )	\
		{																								\
			portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) );							\
		}																								\
	}

#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */

查找最高优先级的就绪任务有两种方法 ,具体由 configUSE_PORT_OPTIMISED_TASK_SELECTION 这个宏控制,定义为 0 选择通用方法, 定义为 1 选择根据处理器优化的方法。

该宏默认在 portmacro.h 中定义为 1,即使用优化过的方法。

/* Port specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
	#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif

通用方法:

taskRECORD_READY_PRIORITY()用于更新 uxTopReadyPriority的值。uxTopReadyPriority 是一个在 task.c 中定义的静态变量,用于表示创建的任务的最高优先级,默认初始化为 0,即空闲任务的优先级。

	#define taskRECORD_READY_PRIORITY( uxPriority )														\
	{																									\
		if( ( uxPriority ) > uxTopReadyPriority )														\
		{																								\
			uxTopReadyPriority = ( uxPriority );														\
		}																								\
	} 

taskSELECT_HIGHEST_PRIORITY_TASK()用于寻找优先级最高的就绪任务,实质就是更新 uxTopReadyPriority 和 pxCurrentTCB 的值。
通用方法查找优先级最高的就绪任务的方法是通过while循环,从已知的最高优先级对应的就绪列表数组下标开始顺序往下寻找当前链表下是否有任务存在,直到找到最高优先级的就绪任务。 之所以可以采用从最高优先级往下搜索,是因为任务的优先级与就绪列表的下标是一一对应的,优先级越高,对应的就绪列表数组的下标越大。

	#define taskSELECT_HIGHEST_PRIORITY_TASK()															\
	{																									\
	UBaseType_t uxTopPriority = uxTopReadyPriority;														\
																										\
		/* Find the highest priority queue that contains ready tasks. */								\
		while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) )							\
		{																								\
			configASSERT( uxTopPriority );																\
			--uxTopPriority;																			\
		}																								\
		listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );			\
		uxTopReadyPriority = uxTopPriority;																\
	} /* taskSELECT_HIGHEST_PRIORITY_TASK */

	/*-----------------------------------------------------------*/
	#define taskRESET_READY_PRIORITY( uxPriority )
	#define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )

优化方法:

taskRECORD_READY_PRIORITY()用于根据传进来的形参(通常形参就是任务的优先级)将变量 uxTopReadyPriority 的某个位置 1。uxTopReadyPriority 是一个在 task.c 中定义的静态变量,默认初始化为 0。与通用方法中用来表示创建的任务的最高优先级不一样,它在优化方法中担任的是一个优先级位图表的角色,即该变量的每个位对应任务的优先级,如果任务就绪,则将对应的位置 1,反之清零。根据这个原理,只需要计算出 uxTopReadyPriority 的前导零个数就算找到了就绪任务的最高优先级。与taskRECORD_READY_PRIORITY() 作 用 相 反 的 是taskRESET_READY_PRIORITY() 。

#define taskRECORD_READY_PRIORITY( uxPriority )	portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )

taskRESET_READY_PRIORITY()用于根据传进来的形参(通常形参就是任务的优先级)将变量 uxTopReadyPriority 的某个位清零。
有个if判断条件是要先确保就绪列表中对应该优先级下的链表没有任务才能改变uxTopReadyPriority对应的位。

	#define taskRESET_READY_PRIORITY( uxPriority )														\
	{																									\
		if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 )	\
		{																								\
			portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) );							\
		}																								\
	}

portRECORD_READY_PRIORITY和portRESET_READY_PRIORITY定义在portmacro.h 中:

#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )

taskSELECT_HIGHEST_PRIORITY_TASK()用于寻找优先级最高的就绪任务,实质就是更新 uxTopReadyPriority 和 pxCurrentTCB 的值。

	#define taskSELECT_HIGHEST_PRIORITY_TASK()														\
	{																								\
	UBaseType_t uxTopPriority;																		\
																									\
		/* Find the highest priority list that contains ready tasks. */								\
		portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );								\
		configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 );		\
		listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );		\
	}

portGET_HIGHEST_PRIORITY在 portmacro.h 中定义

#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities )\
uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )

在第二种优化方法中,变量uxTopReadyPriority 的每个位号对应的是任务的优先级,任务就绪时,则将对应的位置 1,反之则清零。
使 用 前 导 零 指 令 __CLZ(uxTopReadyPriority)可以很快的计算出 uxTopReadyPriority 的前导零的个数,通过前导零的个数能定位到uxTopReadyPriority最高非0位,也就能快速定位到最高就绪任务优先级。

调用:

任务切换函数vTaskSwitchContext()直接调用函数taskSELECT_HIGHEST_PRIORITY_TASK()寻找到优先级最高的就绪任务的 TCB,然后更新到 pxCurrentTCB。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/925072.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android studio 点击按钮 (跳转界面)

Android studio 点击按钮 &#xff08;跳转界面&#xff09; 问题描述 首先&#xff0c;我们有两个Java文件和与之绑定的xml文件。此处以HistoryActivity.java&#xff0c;activity_history.xml 和 EventDetail.java&#xff0c;activity_event_detail.xml为例子。我们要实现…

05-Numpy基础-用于数组的文件输入输出

np.save和np.load是读写磁盘数组数据的两个主要函数。默认情况下&#xff0c;数组是以未压缩的原始二进制格式保存在扩展名为.npy的文件中的&#xff1a; 如果文件路径末尾没有扩展名.npy&#xff0c;则该扩展名会被自动加上。然后就可以通过np.load读取磁盘上的数组&#xff1…

NAT网关

NAT网关 NAT网关(NAT Gateway)是一种网络地址转换服务&#xff0c;提供NAT代理(SNAT和DNAT)能力。阿里云NAT网关分为公网NAT网关和VPC NAT网关&#xff1a; ■ 公网NAT网关提供公网地址转换服务 ■ VPC NAT网关提供私网地址转换服务 公网NAT网关 公网NAT网关是一款针对公网访…

Matlab分割彩色图像

彩色图像 彩色图像除有亮度信息外&#xff0c;还包含有颜色信息。以最常见的RGB&#xff08;红绿蓝&#xff09;彩色空间为例来简要说明彩色图像&#xff1a; 彩色图像可按照颜色的数目来划分。例如&#xff0c;256色图像和真彩色图像&#xff08;2的16次方&#xff1d;21677…

解决Android Studio中Plugin version和Gradle version不匹配的问题

生命中最艰难的那段路是要自己一个人走过来的&#xff0c;这样&#xff0c;学到更多的是坚强&#xff0c;而不是感动。 《红猪》 前言 导入一个百度云的Demo而已&#xff0c;居然遇到这么多问题&#xff0c;纠结了很久&#xff0c;也查了很多资料&#xff0c;弯弯绕绕了好多路…

Ae 效果:CC Light Wipe

过渡/CC Light Wipe Transition/CC Light Wipe CC Light Wipe&#xff08;CC 光线擦除&#xff09;可以为图层添加指定形状&#xff08;圆形、门形和方形&#xff09;的光效&#xff0c;并通过光效形状的开合来实现擦除过渡。 可以为要过渡到的图层添加“曝光度”等效果&#x…

记Flask-Migrate迁移数据库失败的两个Bug——详解循环导入问题

文章目录 Flask-Migrate迁移数据库失败的两个Bug1、找不到数据库&#xff1a;Unknown database ***2、迁移后没有效果&#xff1a;No changes in schema detected. Flask-Migrate迁移数据库失败的两个Bug 1、找不到数据库&#xff1a;Unknown database ‘***’ 若还没有创建数…

有哪些前端调试和测试工具? - 易智编译EaseEditing

前端开发调试和测试工具帮助开发人员在开发过程中发现和修复问题&#xff0c;确保网站或应用的稳定性和性能。以下是一些常用的前端调试和测试工具&#xff1a; 调试工具&#xff1a; 浏览器开发者工具&#xff1a; 现代浏览器&#xff08;如Chrome、Firefox、Safari等&#…

Kali个人初始配置

1、修改root密码 sudo passwd root 2、kali换国内源 vim /etc/apt/sources.list&#xff0c;注释掉默认的官方源 deb http://mirrors.aliyun.com/kali kali-rolling main non-free contrib deb-src http://mirrors.aliyun.com/kali kali-rolling main non-free contrib# …

JavaScript箭头函数

Arrow Functions&#xff08;箭头函数&#xff09;是 ES6 中引入的一种新的函数表达式语法&#xff0c;它可以更简洁地定义函数&#xff0c;并且不需要像普通函数一样使用 function 关键字。 例如我们上节课的代码&#xff1a; const peopleAge function calcAge1(birthYear)…

idea新建Java-maven项目时,出现Dependency‘xxx(jar包名)‘ not found的解决方案

项目场景&#xff1a; 项目场景&#xff1a;使用idea创建maven项目时&#xff0c;导入简单依赖时&#xff08;本文以mysql-connector-java为例&#xff09;。 问题描述 问题&#xff1a; 首先&#xff0c;在创建新的maven项目中&#xff0c;出现下列两种情况&#xff1a; &am…

读SQL学习指南(第3版)笔记05_过滤

1. 不需要考虑排除任何列 1.1. 清除数据表中所有的内容 1.2. 暂存新数据仓库的数据 1.3. 向数据表中新添一列后 1.4. 修改数据表中的所有行 1.5. 检索消息队列表中的所有行 2. where子句 2.1. 可以在其中指定一个或多个过滤条件&#xff0c;用于限制SQL语句处理的行数 …

Session 认证机制

什么是 Cookie Cookie 是存储在用户浏览器中的一段不超过 4 KB 的字符串。它由一个名称(Name)、一个值(Value) 和其它几个用于控制 Cookie 有效期、安全性、使用范围的可选属性组成。 不同域名下的 Cookie 各自独立&#xff0c;每当客户端发起请求时&#xff0c;会自动把当前…

destoon8.0自媒体类型综合资讯门户模板

随着时代发展&#xff0c;自媒体资讯适合当前的互联网情形。呕心沥血开发的一套自媒体综合门户网站模板&#xff0c;本模板采用纯手写开发&#xff0c;带会员中心。首页&#xff0c;列表页&#xff0c;内容页&#xff0c;搜索页面精心编写&#xff0c;非常大气&#xff0c;并配…

【stable-diffusion使用扩展+插件和模型资源(下)】

插件模型魔法图片等资源&#xff1a;https://tianfeng.space/1240.html 书接上文&#xff1a;&#xff08;上&#xff09; 插件推荐 1.lobe theme lobe theme是一款主题插件&#xff0c;直接可以在扩展安装 界面进行了重新布局&#xff0c;做了一些优化&#xff0c;有兴趣的…

电商格局大变,刘强东再出重拳力挽狂澜,能挽回用户的心么?

近日中国第三大电商京东宣布将降低免邮门槛&#xff0c;plus用户全年免邮&#xff0c;普通用户免邮门槛从99元降低至59元&#xff0c;显示出创始人刘强东回归后再出重拳&#xff0c;如此做的原因在于国内的电商格局已发生重大变化。 国内的电商格局早已从阿里、京东两强&#x…

webscoket在vue中的使用

项目场景&#xff1a; 提示&#xff1a;项目相关背景&#xff1a; 什么是webscoket&#xff1f;: WebSocket是一种计算机通信协议&#xff0c;通过单个TCP连接提供全双工通信信道。实现了web客户端和服务器之间的实时通信&#xff0c;与传统的HTTP连接相比&#xff0c;允许以…

【洛谷】P1873 [COCI2011-2012#5] EKO / 砍树

原题链接&#xff1a;https://www.luogu.com.cn/problem/P1873 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 二分答案。 3. 代码实现 #include<bits/stdc.h> using namespace std; #define ll long long const int N 1e6 10; int a[N], …

日本核污水排放入海,海洋污染问题再引关注

2023年8月22日&#xff0c;日本政府举行相关阁僚会议后宣布&#xff0c;将从8月24日启动福岛核污染水排海。根据计划&#xff0c;福岛核污染水的排海至少要持续30年。此消息一出&#xff0c;引发国际社会和广大民众的强烈谴责。 福岛第一核电站的核污水含有多种放射性物质。其中…

ARM64函数调用流程分析

ARM64函数调用流程分析 1 ARM64 函数调用实例2 对应代码的分析2.1 main函数及其对应的汇编程序2.1.1 main的C代码实现2.1.2 main函数对应汇编及其分析2.1.3 执行完成之后栈的存放情况 2.2 test_fun_a函数及其对应的汇编程序2.2.1 test_fun_a函数的C实现2.2.2 test_fun_a函数对应…