FreeRTOS内核实现05:支持多优先级

2023-05-16

目录

 

1. 支持多优先级的方法

1.1 任务优先级

1.2 基于优先级的就绪列表

 1.3 实现基于优先级的调度

2. 查找最高优先级就绪任务的方法

2.1 通用方法

2.2 体系结构优化方法

3. 修改代码支持多优先级

3.1 创建任务相关

3.1.1 修改任务控制块

3.1.2 增加prvAddNewTaskToReadyList函数

3.2 修改vTaskSwitchContext函数

 3.3 修改xTaskIncrementTick函数

 3.4 修改vTaskDelay函数

4. 实验现象


1. 支持多优先级的方法

1.1 任务优先级

在FreeRTOS中,使用数字表示任务优先级,数字越小优先级越小(这点和uC/OS & RT-Thread正好相反)

 

说明:后文将看到,FreeRTOS中这种优先级设置方式是和查找优先级最高的就绪任务的方式相匹配的

1.2 基于优先级的就绪列表

/* 任务就绪列表 */
List_t pxReadyTasksLists[configMAX_PRIORITIES];

 ① 就绪列表是一个存储就绪任务TCB的列表数组,元素个数就是系统支持的优先级个数

② 数组的下标对应任务的优先级,优先级越低,对应的数组下标越小。其中空闲任务优先级最低,对应下标为0的列表

③ 任务在创建时,会根据任务的优先级将任务插入到就绪列表不同的位置;相同优先级的任务插入到就绪列表的同一个列表中

 1.3 实现基于优先级的调度

pxCurrentTCB是一个全局的TCB指针,用于指向当前正在运行任务的TCB。要想让任务支持优先级,只要解决在任务切换时让pxCurrentTCB指向最高优先级的就绪任务的TCB即可

下面就说明查找最高优先级就绪任务的方法

2. 查找最高优先级就绪任务的方法

在FreeRTOS中提供2种查找最高优先级就绪任务的方法,

① 通用方法

② 根据特定处理器优化的方法

在编译时由configUSE_PORT_OPTIMISED_TASK_SELECTION宏加以控制

2.1 通用方法

/*
* 系统当前就绪任务最高优先级
* 初始值为0,对应最低优先级的空闲任务
*/
// file: tasks.c
static volatile BaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;

// file: tasks.c
/* 在系统中注册就绪任务优先级 */
#define taskRECORD_READY_PRIORITY(uxPriority) \
{ \
    if ((uxPriority > uxTopReadyPriority)) \
    { \
        uxTopReadyPriority = (uxPriority); \
    } \
}
	
/* 查找优先级最高的就绪任务 */
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
    UBaseType_t uxTopPriority = uxTopReadyPriority; \
    while (listLIST_IS_EMPTY(&(pxReadyTasksLists[uxTopPriority]))) \
    { \
        --uxTopPriority; \
    } \
    listGET_OWNER_OF_NEXT_ENTRY(pxCurrentTCB, \
            &(pxReadyTasksLists[uxTopPriority])); \
    uxTopReadyPriority = uxTopPriority; \
}
	
/* 在系统中注销任务优先级(通用方法为空) */
#define taskRESET_READY_PRIORITY(uxPriority)
#define portRESET_READY_PRIORITY(uxPriority, uxTopReadyPriority)

说明1:uxTopReadyPriority的含义

在通用方法中,uxTopReadyPriority用于记录当前系统中就绪任务的最高优先级,可见该方法无法体现当前系统中哪些优先级是有任务的,这种缺点就限制了通用方法的实现

 

说明2:注册就绪任务优先级

在通用方法中,注册就绪任务优先级就是比较就绪任务优先级与uxTopReadyPriority的大小,使得uxTopReadyPriority中始终记录当前系统中就绪任务的最高优先级

 

说明3:无法注销优先级

在某些情况下,任务是需要退出就绪状态的(e.g. 比如任务进入睡眠或等待资源),此时应该注销该优先级

但是在通用模式下,退出就绪状态的任务并不知道自己是否是最高优先级,所以无法更新uxTopReadyPriority变量

如果要实现更新,就必须在有任务退出就绪状态时从尾部遍历就绪列表,以便更新uxTopReadyPriority变量,但是这个代价是很大的

补充:无法注销优先级还因为要考虑支持同优先级多任务的场景,当从就绪列表注销一个任务时,可能有与该任务同优先级的任务,所以仍需要遍历就绪列表才能正确更新uxTopReadyPriority变量

 

说明4:遍历查找最高优先级任务

正是由于上面提到的不能实时更新uxTopReadyPriority变量,所以在调用taskSELECT_HIGHEST_PRIORITY_TASK时,可能uxTopReadyPriority对应的优先级并没有任务,所以需要从尾部遍历

2.2 体系结构优化方法

/*
* 系统当前就绪任务最高优先级位图
* 初始值为0,对应没有任务
*/
static volatile BaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;

/* 在系统中注册就绪任务优先级 */
// file: portmacro.h
#define portRECORD_READY_PRIORITY(uxPriority, uxTopReadyPriority) \
		(uxTopReadyPriority) |= (1UL << (uxPriority));

// file: tasks.c
#define taskRECORD_READY_PRIORITY(uxPriority) \
		portRECORD_READY_PRIORITY(uxPriority, uxTopReadyPriority)
	
/* 查找优先级最高的就绪任务 */
// file: portmacro.h
#define portGET_HIGHEST_PRIORITY(uxTopPriority, uxTopReadyPriority) \
    uxTopPriority = (31UL - (uint32_t)__clz((uxTopReadyPriority)));

// file: tasks.c
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
    UBaseType_t uxTopPriority; \
    portGET_HIGHEST_PRIORITY(uxTopPriority, uxTopReadyPriority); \
    listGET_OWNER_OF_NEXT_ENTRY(pxCurrentTCB, \
            &(pxReadyTasksLists[uxTopPriority])); \
}

/* 在系统中注销任务优先级 */
// file: portmacro.h
#define portRESET_READY_PRIORITY(uxPriority, uxTopReadyPriority) \
		(uxTopReadyPriority) &= ~(1UL << (uxPriority));

// file: tasks.c
#define taskRESET_READY_PRIORITY(uxPriority) \
{ \
    portRESET_READY_PRIORITY(uxPriority, uxTopReadyPriority); \
}

 说明1:uxTopReadyPriority的含义

在体系结构优化方法中uxTopReadyPriority作为任务就绪位图使用,当某一位为1时,表示对应的优先级有任务就绪

此时很容易通过位操作来注册和注销任务优先级,也就解决了通用方法中的问题

 

说明2:基于clz指令的优化

优化方法的核心是使用clz指令计算uxTopReadyPriority中的先导零个数,进而计算出当前的最高优先级

基于这种优化方式,就很容易理解为什么在FreeRTOS中数字越大优先级越高,因为任务优先级在此处被映射为就绪位图中的位数

 

说明3:再看listGET_OWNER_OF_NEXT_ENTRY宏的使用

#define listGET_OWNER_OF_NEXT_ENTRY(pxTCB, pxList) \
{ \
	List_t *const pxConstList = (pxList); \
	/* 节点索引指向链表第1个节点 */ \
	(pxConstList)->pxIndex = (pxConstList)->pxIndex->pxNext; \
	if ((void *)(pxConstList)->pxIndex == \
        (void *)&((pxConstList)->xListEnd)) \
	{ \
		(pxConstList)->pxIndex = (pxConstList)->pxIndex->pxNext; \
	} \
	/* 获取节点owner */ \
	(pxTCB) = (pxConstList)->pxIndex->pvOwner; \
}

 在列表章节的笔记中曾经谈到过对该宏的使用,对该宏的正确理解应该是用于遍历列表,每调用一次,均会按序返回下一个列表项

当列表非空时,该宏会越过尾节点;如果列表为空,则会出错,因为尾节点中没有pvOwner选项,所以该宏只能在确知列表非空的情况下调用

 

说明4:使用体系结构优化方法的代价就是任务优先级一般不能超过32个,否则无法映射到32位的位图之上

 

补充:FreeRTOS中任务就绪列表视图如下图所示,可见如何将就绪列表状态映射到就绪位图中

3. 修改代码支持多优先级

3.1 创建任务相关

3.1.1 修改任务控制块

typedef struct tskTaskControlBlock
{
    // 其他字段
    UBaseType_t uxPriority; // 任务优先级
} tskTCB;

说明:由于TCB中增加了任务优先级字段,所以用于创建任务的xTaskCreateStatic & prvInitialiseNewTask函数均要增加任务优先级参数

3.1.2 增加prvAddNewTaskToReadyList函数

// file: tasks.c
/* 将pxTCB指向的任务加入就绪列表 */
#define prvAddTaskToReadyList(pxTCB) \
	taskRECORD_READY_PRIORITY((pxTCB)->uxPriority); \
	vListInsertEnd(&(pxReadyTasksLists[(pxTCB)->uxPriority]), \
	               &((pxTCB)->xStateListItem));

static void prvAddNewTaskToReadyList(TCB_t *pxNewTCB)
{
	/* 进入临界段 */
	taskENTER_CRITICAL();
	{
		/* 全局任务计数器加1 */
		uxCurrentNumberOfTasks++;
		
		if (pxCurrentTCB == NULL)
		{
			/* 如果pxCurrentTCB为空,将其指向新创建的任务 */
			pxCurrentTCB = pxNewTCB;
			
			/* 如果是第一次创建任务,需要初始化任务相关列表 */
			if (uxCurrentNumberOfTasks == (UBaseType_t)1)
			{
				prvInitialiseTaskLists();
			}
		}
		else
		{
			/* 如果pxCurrentTCB不为空,则根据任务优先级更新 */
			if (pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority)
			{
				pxCurrentTCB = pxNewTCB;
			}
		}
		
		/* 将任务加入就绪列表 */
		prvAddTaskToReadyList(pxNewTCB);
	}
	/* 退出临界段 */
	taskEXIT_CRITICAL();
}

说明1:在将任务加入就绪列表的同时,修改任务就绪位图,表示该优先级已有任务就绪

 

说明2:pxCurrentTCB的更新

在创建任务的过程中,根据任务优先级更新pxCurrentTCB指针,这样在启动调度器时就可以自动运行当前优先级最高的任务,而不需要手动指定

这里需要注意的是,只有在调度器尚未开始运行时,才可以在prvAddNewTaskToReadyList函数中切换pxCurrentTCB指针的指向。如果调度器已经运行,则只能等待任务调度

3.2 修改vTaskSwitchContext函数

现在的调度变得非常简单,就是查找优先级最高的就绪任务

// file: tasks.c

void vTaskSwitchContext(void)
{
	/* 获取优先级最高的就绪任务的TCB,然后更新到pxCurrentTCB */
	taskSELECT_HIGHEST_PRIORITY_TASK();
}

 3.3 修改xTaskIncrementTick函数

// file: tasks.c

void xTaskIncrementTick(void)
{
	TCB_t *pxTCB = NULL;
	BaseType_t i = 0;
	
	const TickType_t xConstTickCount = xTickCount + 1;
	xTickCount = xConstTickCount;
	
	/* 更新任务延时计数 */
	for (i = 0; i < configMAX_PRIORITIES; i++)
	{
		pxTCB = (TCB_t *)listGET_OWNER_OF_HEAD_ENTRY(
                              &(pxReadyTasksLists[i]));
		if (pxTCB->xTicksToDelay > 0)
		{
			pxTCB->xTicksToDelay--;
			
			/* 延时到达,将任务就绪 */
			if (pxTCB->xTicksToDelay == 0)
			{
				taskRECORD_READY_PRIORITY(pxTCB->uxPriority);
			}
		}
		
		/* 触发任务切换 */
		portYIELD();
	}
}

说明:现在递减任务延时的方式仍然是遍历任务就绪列表,这样效率太低,后续将实现任务延时列表,专门用于维护处于延时状态的任务

 3.4 修改vTaskDelay函数

void vTaskDelay(const TickType_t xTicksToDelay)
{
	TCB_t *pxTCB = NULL;
	
	/* 获取当前任务TCB */
	pxTCB = pxCurrentTCB;
	
	/* 设置延时Tick值 */
	pxTCB->xTicksToDelay = xTicksToDelay;
	
	/* 将任务从就绪列表中删除 */
	taskRESET_READY_PRIORITY(pxTCB->uxPriority);
	
	/* 主动放弃CPU */
	taskYIELD();
}

说明:此处并未真的将任务从就绪列表中删除,因为xTaskIncrementTick函数还需要遍历就绪列表维护延时tick值,此处只是注销了任务优先级

设想一下,如果此时同优先级有多个任务,简单注销任务优先级也是不合理的。这就促使我们一定要实现延时列表,将需要延时的任务移出就绪列表

4. 实验现象

说明1:实验现象和上一章是相同的,差别在于现在是根据任务优先级调度,而之前是人为在Task1和Task2之间切换

 

说明2:在当前代码环境下,通用模式是不能工作的,因为我们没有将退出就绪状态的任务移出就绪列表,在调用taskSELECT_HIGHEST_PRIORITY_TASK宏从尾部遍历就绪列表时,优先级永远不会改变,导致只有一个高优先级任务被调度

在下个章节完成任务延时列表后将再次验证

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS内核实现05:支持多优先级 的相关文章

  • 状态机编程思维学习笔记(C语言)

    前言 不摸鱼摆烂的第一天 目录 前言C语言面对对象特性引入函数指针结构体中套用函数指针宏定义中 纯替换 状态机概念状态机实现后文 C语言面对对象特性引入 众所周知 xff0c C 43 43 是由C语言编写而成 xff0c 因此 xff0c
  • stm32串口中断收发数据环形缓冲区的设计

    Function Name USART2 IRQHandler Description This function handles USART2 global interrupt request Input None Output None
  • 多线程的守护线程和等待线程结束方法

    守护线程的含义是 xff1a 如果当前运行的所有线程都是守护线程 xff0c 则程序直接结束 package thread 64 ClassName Test7 64 Author 瞿肖 64 Date 2022 7 11 14 32 pu
  • 用数学规划的方式求解优化问题

    本文介绍如何用数学语言对实际中的优化问题进行建模 通过建立数学模型 我们利用现成的求解器可以便捷地计算出最优解 或可行解 运输问题 考虑三个粮食储量分别是100 200 300的仓库 单位 吨 下文省略 我们需要把粮食运送给4个客户 其需求
  • 操作系统磁盘管理

    文章目录 01 知识概述部分02 课程知识回顾说明03 磁盘管理知识体系结构04 磁盘管理物理结构05 磁盘管理分区操作问题 xff1a 新添加硬盘无法识别 分区操作1 xff1a fdisk xff08 操作时可看10点的视频 xff09
  • ROS学习——Rviz(更新中)

    固定架 两个框架中最重要的是固定框架 固定框架是用于表示 世界 框架的参考框架 这通常是 地图 或 世界 或类似名称 xff0c 但也可以是例如里程表框架 如果将固定框架错误地设置为例如机器人的底座 xff0c 则机器人曾经见过的所有物体都
  • Boost型Ladrc控制双闭环电路 双闭环控制

    Boost型Ladrc控制双闭环电路 双闭环控制 xff08 1 xff09 电压外环采用简化Ladrc控制器 xff0c 简化线性自抗扰控制 xff0c 采用PD控制 43 三阶LESO状态观测器 xff0c xff08 2 xff09
  • 【STM32】HAL库——串口中断通信(二)

    由于调试过程中发现Proteus 8有些许bug xff0c 串口中断采用STM32F103RCT6开发板进行讲解 前期准备 xff1a STM32CubeMXSTM32F103RCT6开发板IDE Keil xff08 MDK ARM x
  • Detected problems with API compatibility...修复

    Detected problems with API compatibility 修复 一 xff0c Detected problems with API 问题产生 博主接手年代过于老旧项目 xff0c 在最新安卓版本P等都会出现该弹窗提
  • docker 标记(Tag),推送(push),拉取(pull)你自己的镜像

    链接 https blog csdn net jpiverson article details 50731568 里面的有很详细的步骤和见解 1 输入docker images命令来查看当前的镜像列表 2 找到镜像的id 3 使用IMAG
  • ASSERT: "false" in file qasciikey.cpp, line 501

    pycharm利用moba xterm的x server远程开发 xff0c 在用cv2显示图片时报错 xff1a ASSERT 34 false 34 in file qasciikey cpp line 501 代码 xff1a cv2
  • nvidia-smi命令输出结果缓慢

    可能的原因和解决办法 xff1a 当前已经打开了节能模式 xff08 需要关闭节能模式 xff0c 切换到持久模式 xff09 如何关闭节能模式 xff1a span class token comment 修改或创建配置文件 span s
  • ESP8266深度学习之一初识设备

    一 ESP8266是什么 xff1f 总的来说ESP8266是一款单片机 xff0c 而且是一款自带WIFI功能的单片机 它是安信可公司众多单片机中的一种 xff0c 同时它也有很多种型号可以供我们选择使用 二 ESP8266有什么特点 x
  • 什么是RTK?

    国内习惯把GNSS接收机叫成RTK这倒是真的 xff0c 因为RTK技术的普及 xff0c 让大家对接收机的作用就 限定 在了RTK xff0c 在之前没有RTK时 xff0c 接收机就是接收机 目前 xff0c GNSSj接收机约99 的
  • STM32F103VCT6 高级定时器的PWM输出

    要求得到下列波形 xff0c 死区时间1us CH1和CH1之间的相位差事3us 频率50HZ 1 xff0c To get TIM1 counter clock at 72MHz the prescaler is computer as
  • 计算机视觉(相机标定;内参;外参;畸变系数)

    目录 一 预备知识 1 坐标系变换过程 xff08 相机成像过程 xff09 xff08 1 xff09 相机坐标系转换为图像坐标系 xff08 透视投影变换遵循的是针孔成像原理 xff09 xff08 2 xff09 齐次坐标的引入原因
  • ROS基础(2)——工作空间

    一 工作空间 1 工作空间的概念 ros工作空间简单来说相当于工程或者项目 xff0c 编写ros程序之前 xff0c 首先需要创建ros工作空间 2 创建工作空间 span class token function mkdir span
  • Ubuntu18.04完整新手安装教程和分区设置

    作者PS xff1a 好久没关注blog了 xff0c 居然这么多同学看了这篇文章 xff1a xff09 注意注意 xff1a 以下是关键总结 xff1a 分区 xff1a 这三个就够了 xff1a xff0c home xff0c sw
  • ROS基础(4)——安装ROS相关软件包

    一 ROS的两种安装方式 本章将会通过两种安装方式安装ROS相关软件包 分别是 xff1a 通过apt方式安装RoboWare Studio 通过下载源码编译的方式安装安装ROS Academy for Beginners教学包 这是两种常
  • arm与51单片机之间串口通信实验

    这几天弄arm的串口通信 xff0c 因为以前有点单片机的基础 xff0c 于是 就选了块51单片机与其实验 实验内容是在linux下编写好串口通信程序 xff0c 编译后下载到arm板上运行 xff0c 验证其可行性 linux下串口程序

随机推荐

  • ROS源代码阅读(8)——定位

    2021SC 64 SDUSC ROS源代码阅读 xff08 8 xff09 SLAM定位 xff1a 机器人定位的方法可以分为非自主定位与自主定位两大类 非自主定位是在定位的过程中机器人需要借助机器人本身以外的装置如 xff1a 全球定位
  • 博途V15

    西门子 博途V15仿真报错 WIN10虚拟机安装博途V15 xff0c 仿真时出现如下报错 无法找到STEP 7 V15许可证 开始以为是许可证问题 xff0c 找了18和19的Sim EKB Install进行激活 xff0c 但是并没有
  • Jetson TX2入门之开箱刷机跑demo

    Jetson TX2 开箱配置 43 刷机 43 跑demo xff08 常见坑总结 xff09 简介 JetSon系列是Nvidia公司推出的面向无人智能化领域的嵌入式平台 xff0c 这块嵌入式板子的出现使得我们可以在边缘设备上处理复杂
  • 集成显卡安装pytorch

    Inter集成显卡安装pytorch 安装pytorch 计算机右键 管理 gt 设备显示器 gt 显示适配器 xff0c 查看显卡 我的电脑只有Inter的集成显卡 xff0c 没有独显 刚开始接触 xff0c 对GPU不懂 xff0c
  • ROS可视化动态查看所有topic的频率/带宽/消息类型/数值

    在程序运行或者回放数据包时 xff0c 希望实时查看到所有的正在向外发送的topic名字 类型 带宽 频率 数值等 除了rostopic list以外还可使用rqt辅助包 打开rqt rqt 选择Plugins插件 Topics信息 top
  • PID与MPC控制方法

    记录udacity 无人驾驶工程师课程中控制部分 MPC代码和实践链接https github com udacity CarND MPC Quizzes 本文按照对udacity课程的理解和翻译而来 1 PID P xff1a Propo
  • C++STL容器及其优缺点介绍

    STL容器介绍及选择方式 容器类型容器优缺点一 序列容器vectordequelistforward list xff08 C 43 43 11 xff09 queuepriority queue stackarray 二 关联容器setm
  • word中插入noteExpress和页码出现乱码解决方法

    在word中出现页码变成PAGE MERGEFORMAT xff0c noteExpress插入的代码也变成了乱码 打开出问题的word文档 xff0c 按照如下设置 xff1a 文件 选项 高级 显示文档内容 不勾选显示域代码而非阈值 修
  • FreeRTOS内核实现04:空闲任务与阻塞延时

    目录 1 引入原因 2 实现空闲任务 2 1 定义空闲任务组件 2 2 创建空闲任务 3 实现阻塞延时 3 1 vTaskDelay函数实现 3 2 修改vTaskSwitchContext函数 3 3 SysTick初始化函数实现 3 4
  • NoteExpress对参考文献格式修改

    文章目录 NoteExpress格式修改1 将带DOI的模板另存为 Revised GBT 7714 20152 编辑自定义的nes文件3 保存选择使用 NoteExpress参考文献格式修改规则GTB 7714 2015下载 NoteEx
  • ubuntu Nvidia显卡驱动安装后 屏幕不能外接显示(扩展显示)的问题

    文章目录 结论安装历程问题详细描述解决方法 结论 配置文件 etc X11 xorg conf未正确配置 xff0c 安装历程 安装显卡驱动后 xff0c 依旧无法正常扩展屏幕显示 xff0c 仔细一看发现在nvidia smi时出现No
  • ubuntu 16.04无法locate boot-repair的解决方法

    ubuntu16 04 07加windows10后无法启动ubunu的问题解决boot repair的安装方法同样适用于ubuntu18 04 ubuntu20 01等系统不能启动的问题 对boot repair修复的原理进行分析 文章目录
  • 论文降低word大小——图像免费压缩方法

    在期刊和毕业论文提交盲审过程中 xff0c 时常对word和pdf的大小进行限制 xff0c 但是在多图的论文中 xff0c 将大小限制在20MB以内较为困难 梳理以下两种方法 xff1a 1 visio图片大小压缩 visio图片插入到w
  • C/C++获取路径下所有文件及其子目录的文件名

    一 功能描述 需要提取某个文件夹下所有文件名字 xff0c 当包含子目录时 xff0c 将子目录及其路径获取到 二 实现方式 使用C语言的opendir函数 DIR span class token operator span dp spa
  • C/C++删除目录文件夹下所有文件(递归)

    一 问题 想要删除目录文件夹 xff0c 类似于rm r的操作 方式1 xff1a 可以使用system直接执行rm r的指令 xff0c system 34 rm r 34 方式2 xff1a 通过C语言内置的函数remove和rmdir
  • Git GUI 的使用

    权限校验 首先 xff0c 服务器需要身份识别 一段RSA加密字符串 启动GUI xff0c 菜单 帮助 Step1 创建密钥 Generate SSH KEY Step2 添加密钥 去你的代码托管服务器 xff0c 你的账号设置中 xff
  • 推荐系统遇上深度学习(九)--评价指标AUC原理及实践

    欢迎关注天善智能 xff0c 我们是专注于商业智能BI xff0c 人工智能AI xff0c 大数据分析与挖掘领域的垂直社区 xff0c 学习 xff0c 问答 求职一站式搞定 xff01 对商业智能BI 大数据分析挖掘 机器学习 xff0
  • VR版“半条命”大火,VR游戏迎来消费级市场的春天?

    彼之砒霜 xff0c 汝之蜜糖 2020年的艰难开局 xff0c 在让众多行业陷入困顿之际 xff0c 却让游戏业迎来了一场流量的盛宴 除了日进斗金的王者 吃鸡 xff0c 还有火爆朋友圈的动森 xff0c 一款3A级VR游戏 Half L
  • 读懂海尔智家大脑:深度体验的本质是深度生活

    了解科技行业的读者 xff0c 应该都对 大脑 这个名词不陌生 黑灯工厂 里指挥生产的 工业大脑 xff0c 繁忙机场里运筹帷幄的 航空大脑 xff0c 还有智慧城市建设的灵魂 城市大脑 如果家也有一颗总揽全局的大脑 xff0c 生活会发生
  • FreeRTOS内核实现05:支持多优先级

    目录 1 支持多优先级的方法 1 1 任务优先级 1 2 基于优先级的就绪列表 1 3 实现基于优先级的调度 2 查找最高优先级就绪任务的方法 2 1 通用方法 2 2 体系结构优化方法 3 修改代码支持多优先级 3 1 创建任务相关 3