freeRTOS任务调度及其通信

一、FreeRTOS任务

在多数通用操作系统(如Linux、Windows等)中,线程为系统的调度最小单元,进程为独立应用程序的最小运行过程。而在实时操作系统中,多数情况下不区分线程与进程进行独立管理,为了减小系统资占用以及提高实时性,往往将线程与进程合二为一,采用任务作为应用程序的最小调度运行单元,使用TCB(任务控制块)对任务进行管理。FreeRTOS作为常用的RTOS系统中的一员,它的任务调度以及任务之间的通信的设计遵从多数RTOS的设计。FreeRTOS简捷、方便、易用的任务机制,是其近几年成为市场份额最大的RTOS因素之一,本文主要对其任务调度实现以及通信原理进行描述介绍。

二、FreeRTOS任务调度

FreeRTOS的任务被动态创建或者静态创建后,不进行删除,目前具备的任务运行态为Running态、Ready态、Blocked态以及Suspended态四个状态。从FreeRTOS官方给出任务资料以及任务状态示意图可以看出,任务的调度主要分为三大阶段:

阶段一:任务创建与调度器启动阶段(下图蓝色部分)

阶段二:任务运行后,调用任务API或者调度器仲裁切换任务状态阶段(下图绿色部分)

阶段三:任务删除销毁阶段(下图红色部分)

07b5e268ae47e40b0645e8473b1e95d2.png

1. 任务创建启动阶段

FreeRTOS调用xTaskCreate(动态创建)或者xTaskCreateStatic(静态创建)API进行任务的创建。动态创建任务时,为任务申请任务堆栈、申请任务控制块(TCB)内存、初始化申请到的内存、调用prvInitialiseNewTask函数初始化任务、最后调用prvAddNewTaskToReadyList函数将新建的任务加入就绪任务列表中(如下官方代码)。

211deb4cf4bae6d5eaf5977c16eed58a.png

创建完成任务后,多数情况下紧随其后调用任务API函数vTaskStartScheduler开启任务的调度。以采用动态创建任务的方式为例,vTaskStartScheduler函数中先是创建空闲任务(idle任务)、若使用软件定时器创建软件定时器、关闭中断、标记调度器开始运行、若配置时间统计开启时间统计功能、调用xPortStartScheduler函数(此函数适配不同的硬件平台,一般用于初始化硬件资源,滴答定时器等;如cortex-m系列用于初始化FPU单元、滴答定时器、PendSV中断等),流程如下图。

3ab088f7c92c922c82de9c681d6ddaa8.png

2. 任务运行阶段

任务在调度器启动后,在创建的任务未被删除销毁之前,任务会在Running(运行)、Ready(就绪)态Blocked(阻塞)以及Suspended(挂起)四个状态中进行切换。

运行态的任务调用系统延时函数(如vTaskDelay函数)、调用ulTaskNotifyTake等待通知、调用xSemaphoreTake等待信号量等行为进入阻塞状态;正在运行的任务死等资源或者调用vTaskSuspend接口可以将自身挂起;正在运行的任务因被中断或者优先级高于或等于(时间片轮转方式使能)的任务打断进入就绪的任务队列中。

阻塞态的任务等到所需的资源或者调用的系统等待时间到点后,会被唤醒重新进入就绪任务列表中;此外也可以通过使用xSemaphoreTake接口将阻塞的任务挂起。

挂起态的任务只能通过调用系统API接口vTaskResume函数恢复到就绪的队列中,挂起态任务只能切换到就绪态。

就绪态的任务在调度器仲裁获取到CPU的执行权后,直接进入运行态,并且可以通过使用vTaskSuspend接口将其挂起。

FreeRTOS的运行态与就绪态之间的切换主要依赖调度器进行仲裁,仲裁算法同时支持优先级抢占式以及时间片调度方式(使能configUSE_PORT_OPTIMISED_TASK_SELECTION=1)。

第一种为优先级抢占的方式:FreeRTOS使用vTaskSwitchContext系统API函数进行任务之间切换,调用taskSELECT_HIGHEST_PRIORITY_TASK()函数仲裁,根据任务优先级获取下一个运行的任务,vTaskSwitchContext函数原型如下:

3c23780838ed9e161dc48310c799e0e5.png

第二种为时间片轮转的调度方式:FreeRTOS使能时间片轮转的方式后,FreeRTOS提供系统API接口xTaskIncrementTick函数进行同个优先级的任务进行时间片轮转调度,每个时间片大小一般为滴答定时器的中断周期。多数情况下会在滴答定时器的中断回调中调用xTaskIncrementTick函数判断是否进行同个优先级任务的轮询切换(若任务在某一个滴答时钟周期内执行完毕,会强制调用portYIELD接口进行任务切换,放弃剩余的时间片时间)。如下图所示,TaskA的优先级等于TaskB,滴答定时器周期为1ms。

58cfa6dedd18d149012cbdbb03633c8b.png

3. 任务删除销毁阶段

就绪、阻塞、挂起的任务都可以调用vTaskDelete系统API接口将其进行删除销毁,被销毁的任务的任务控制块(TCB)以及任务堆栈会在进入idle任务后,在idle任务中进行删除以及释放。

三、任务通信

FreeRTOS具有一般操作系统都具备的几种任务之间的通信方式,提供给用户的常用的通信方式有:消息队列、信号量、互斥锁(互斥信号量)、事件标志组以及任务通知等。

FreeRTOS的任务通知具有32位的消息通知值,只有一个任务接收任务通知,可以减少RAM的使用,运行效率比二值信号量快45%(官方给出的数据)。

事件标志组与信号量的在于:时间标志组主要用与某个任务与多个事件进行同步,或者某个任务与多个任务进行同步。

1. 信号量

FreeRTOS的信号量主要用于某个任务与单个事件或任务进行同步,FreeRTOS常用的信号量为以下几种:

a. 二值信号量

b. 计数型信号量

c. 互斥信号量

d. 递归互斥型号量

以下为官方提供的二值信号量Gif图演示信号量的基本工作原理:

a8b292af5f346457bb5a539d5e37657a.gif

2. 消息队列

FreeRTOS的消息队列主要用于任务中传递大量的消息,以下为官方提供的消息队列Gif图演示消息队列的基本工作原理:

88ab6cf45cf6b7a8846a7697a14013a2.gif


四、小结

 FreeRTOS的不同优先级的任务采用强抢占式调度(高优先抢占)保持其作为RTOS特有实时性,同级优先级的任务采用时间片轮转的方式兼顾同级平等的得到调度运行。任务与任务之间,提供信号量、消息队列、通知、事件标志组等方式进行通信,确保中断事件与任务、任务与任务之间可以有效、高效地进行通信。又因其特有免费开源的特性,使其在RTOS的市场占有份额越来越高。

参考文献

FreeRTOS官方文档:https://www.freertos.org/features.html

FreeRTOS官方代码:https://www.freertos.org/a00104.html

04eda37cf58032474054d3b3a134103f.gif

长按关注

内核工匠微信

Linux 内核黑科技 | 技术文章 | 精选教程

  • 7
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OPPO内核工匠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值