number headings: auto, first-level 2, max 6, 1.1
2 通用部分
2.1 FreeRTOS中如何实现任务间通信
- FreeRTOS中没有进程的概念,所有线程中都可以互相使用对应的内存地址,因此FreeRTOS中任务或线程间的通信可以直接使用普通操作系统中线程通信的方法,比如信号量等。互斥锁本质也是信号量的一种。
- 此外,FreeRTOS中还支持使用队列进行任务间通信,信息发送者调用对应的信息发送方法,接收者调用接收方法。这两个方法都可能发生阻塞,例如当请求发送时队列已满,或者请求接收时队列已空时均会发生阻塞。不过在调用时都可以设置超时时间。
- 此外,也可以使用事件进行任务间通信,事件组允许同时发送组内的多个事件。接受者直接使用
WaitBits
方法即可等待事件,且该方法允许设置超时时间。
- 此外还有一些专门用于特殊场合的通信方式,比如使用任务通知
TaskNotify
,该方法允许更快地将事件传递到接收者(比信号量、队列、事件组都快)。
2.2 讲一下FreeRTOS中的队列
- FreeRTOS的队列主要用于任务间的通信和同步,从而避免了多线程之间的互斥、竞争与同步问题。
- 其使用步骤是创建队列、发送数据和接收数据。其在创建时需要指定元素大小和元素数量,当队列为空时发出接收数据请求时会被阻塞,当队列满时发出发送数据请求均会被阻塞。其阻塞的最大等待时间可以设置。
- 需要注意的是,中断中使用这种在普通状态下可能会导致阻塞的接口时,必须使用其对应的中断版本,即
xxxFromISR
。中断版本的接口是无阻塞的,因此必须需要注意完善对应的逻辑。
2.4 讲一讲什么是优先级反转,如何解决优先级反转
- 优先级反转问题指的是高优先级任务被低优先级任务无意间阻塞,从而在现象上表现为 "优先级反转" 。
- 一个最基本的例子就是某低优先级任务先占用了某个资源但是一直不释放,高优先级任务后申请该资源导致一直被阻塞。这种例子是最简单最核心的例子,但是一般不会直接构成长期持有资源不释放的这种低级错误。
- 考虑一个间接构成的情况:
- 有如下三个任务:
- 高优先级任务H,需要持有资源A,但是比L后申请。
- 中优先级任务M,不需要资源,一直就绪。
- 低优先级任务L,持有资源A,并且就绪。
- 则此时CPU会一直执行任务M,就会表现为任务M的优先级比H高。
- 为了解决这个问题,可以考虑如下的解决方案:
1. 优先级继承:当低优先级任务L需要使用与高优先级任务H共享的资源时,暂时性的将低优先级任务优先级拉到与高优先级相等的优先级,避免被其他中优先级任务中断。
2. 优先级天花板:确保所有任务在尝试获取资源之前先提升到最高的相关优先级,以避免中优先级任务的干扰。(与上一方法本质一直,都是避免中优先级任务打扰)
3. 尽可能的避免使用共享资源
PS:优先级反转的经典例子就是1997年火星探测器"探路者"号的优先级反转问题。(不用背,了解即可)
2.5 如何在FreeRTOS中检测和定位内存溢出
2.6 如何合理地设置任务栈大小
- 先使用有较大运存的平台进行开发,在开发时给对应任务分配足够多的内存,确保不会出现栈溢出的情况。
- 在测试时尽可能的触发最复杂的情况,并调用FreeRTOS中的API来监控每个任务使用的最大占空间。
- 将记录到的最大占空间乘上1.5或2.0作为任务栈大小。
2.7 前后台系统与实时操作系统的区别是什么
- 前后台系统是指将任务分类为前台任务和后台任务的系统,其前台任务往往承担着用户交互、音视频播放等更为重要的任务,因此前台任务的响应优先级更高。而后台任务则反之。
- 前后台系统的问题是在前台任务较多或任务较重的情况下,后台任务可能会饥饿。其总体实时性较低,调度模型为优先级调度。
- 而实时操作系统使用了时间片轮转等调度系统,其更能保证任务响应的实时性。
2.8 剥夺型内核和不可剥夺型内核的区别
- 不可剥夺型内核是指在执行任务过程中,一个任务可以一直运行,只有当前运行的任务主动放弃CPU控制权才会进行任务切换。
- 可剥夺型内核是指系统可以强制中断正在执行的任务,并将控制权交给其他高优先级的任务。
- 而FreeRTOS和Linux都是剥夺型内核,FreeRTOS通过时间片轮转来实现任务切换。
2.9 [TODO]讲一下FreeRTOS的启动流程
2.10 [TODO]讲一下FreeRTOS如何完成任务切换
2.12 什么是任务控制块
- 任务控制块TCB本质就是一个数据结构,是一个结构体,存储的有任务的属性信息以及相关参数,例如任务的堆栈指针、任务优先级、任务名等。每一个任务都有其任务控制块。
- 任务控制块在内核中会被用于操作和处理所有与任务有关的功能,例如:
- 内核通过TCB进行任务调度,调度时会把任务的上下文暂存到TCB,任务恢复时再从TCB恢复现场。
- 内核通过TCB进行资源管理、资源监视等功能。
- 内核通过TCB完成任务间的通信与同步。
- 任务控制块可以通过
FreeRTOSConfig.h
进行裁剪。
2.13 [TODO]介绍一下FreeRTOS内核的基本组成
2.14 讲一讲FreeRTOS如何移植
- 去FreeRTOS官网下载源码,官方提供了平台版本和LTS版本的源码,其主要区别在于LTS中提供的Demo数量比普通版本要少。
- 然后从FreeRTOS中提取kernel的源文件、头文件,再去指定编译器和平台所属文件夹下提取
port.c
和 portmacro.h
。随后提取平台对应的 FreeRTOSConfig.h
。
- 然后配置中断,主要需要配置
PendSV
、 SVC
、 Systick
中断。需要注意的是这些中断必须直接映射,不可在原中断函数中二次转发。
- 创建一个主任务,随后启动FreeRTOS调度器即可正常使用。
3 内存管理
3.2 FreeRTOS中释放内存时,系统如何知道要释放多大的内存
4 多任务
4.1 FreeRTOS中中断如何处理
在FreeRTOS中,中断服务程序(ISR)的处理主要需要考虑如下几个方面:
- 在响应速度上要尽可能快,可以参考Linux内核对于中断例程的处理思路,将中断例程分为上半部和下半部两部分,将需要快速响应的部分留在中断例程中处理,将可以暂缓执行的下半部分使用任务通知(
TaskNotify
)或者主动触发任务切换( portYIELD
)来给予其他线程信号并在对应线程中处理。
- 根据中断优先级的高低可以分为两类:
- 中断优先级高于FreeRTOS中的最大中断优先级的中断,这类中断不会被FreeRTOS禁止,也不会被FreeRTOS内核延迟。这类中断中不可使用任何FreeRTOS提供的API,以避免优先级反转问题。因此在此类中断中可以设置比FreeRTOS中更为紧要的事件,例如无人机的碰撞检测。
- 中断优先级低于等于FreeRTOS中的最大中断优先级的中断,这类中断中可以使用
FromISR
版本的API。
4.2 FreeRTOS中断结束后回到任务时都做了什么
4.4 为什么任务切换通常使用PendSV而非类似于定时器的其他中断
- PendSV是:
- 现在我们假设使用普通定时器中断实现任务切换功能,则可以考虑如下问题: