当前位置: 首页 > news >正文

FreeRTOS 任务通知浅析

FreeRTOS 任务通知浅析

概述

FreeRTOS 提供了任务间传递信息的机制。任务可以等待一个通知信息进入阻塞状态,并在通知信息到来时自动解除阻塞,进入运行的状态。

任务通知是实现任务之间消息传递的机制之一。通常可以让一个A任务进入等待通知的状态,待B任务通知 A 任务后,A 任务继续执行:
在这里插入图片描述
如前所述,任务创建时将分配一块任务控制块(TCB),用于记录该任务的状态、优先级等信息。在该任务控制块中,还记录了与任务通知相关的信息:

volatile uint32_t ulNotifiedValue;// 用来表示通知值
volatile uint8_t ucNotifyState;// 用来表示该任务的通知状态

因此每个任务在创建时都自动地包含一个用来记录当前通知值的 uint32_t 类型的 NotifiedValue,以及一个 记录当前任务通知状态的 uint8_t 类型的 NotifyState。任务之间可以通过更改、查询 NotifiedValue 传递消息。

其中 NotifyState 的取值为:

#define taskNOT_WAITING_NOTIFICATION              ( ( uint8_t ) 0 )  /* 初始状态,不使用任务通知 */
#define taskWAITING_NOTIFICATION                  ( ( uint8_t ) 1 )  /* 使用任务通知,且当前任务处于等待通知的阻塞状态 */
#define taskNOTIFICATION_RECEIVED                 ( ( uint8_t ) 2 )  /* 使用任务通知,且当前任务处于接收到通知的解除阻塞状态,也称为 "pending"(即解除阻塞,有数据未读) 状态*/

任务通知主要有两组 API 组成:

加减1版本操作任意值版本
发送通知xTaskNotifyGivexTaskNotify
接收通知xTaskNotifyTakexTaskNotifyWait

两组 API 的主要区别在于 Give\Take 版本一次只能对 NotifiedValue 加\减1,而Notify\Wait 版本可以对 NotifiedValue 执行更多的运算。

这些 API 的简介如下:

1)

/ *
该函数调用后的行为:
1)使得通知值加一
2)将对应 Task 由阻塞状态解除为非阻塞状态
*/
xTaskNotifyGive(xTaskToNotify // 要通知的任务的句柄
				)

2)

/ *
该函数调用后的行为:
1)进入阻塞,直到接收到通知或者时间超时
2)返回值:函数返回之前,在清零或减一之前的通知值。
*/
ulTaskNotifyTake(xClearCountOnExit, // 退出该函数时如何处理 NotifiedValue,pdTRUE:把通知值清零;pdFALSE:如果通知值大于0,则把通知值减一
					xTicksToWait) // 等待通知的时间

3)

/ *
该函数调用后的行为:
1)使得通知值加一
2)将对应 Task 由阻塞状态解除为非阻塞状态
*/
xTaskNotify(xTaskToNotify, // 要通知的任务的句柄
			ulValue,       // 要通知的任务的NotifiedValue的值
			eAction)       // 对 NotifiedValue 的处理,详细取值见下

其中 eAction 的行为定义如下:

eNoAction	// 仅仅是更新通知状态为"pending"(即解除阻塞),未使用ulValue。这个选项相当于轻量级的、更高效的二进制信号量。
eSetBits	// 通知值 = 原来的通知值 | ulValue,按位或。相当于轻量级的、更高效的事件组。
eIncrement	// 通知值 = 原来的通知值 + 1,未使用ulValue。相当于轻量级的、更高效的二进制信号量、计数型信号量。相当于xTaskNotifyGive()函数。
eSetValueWithoutOverwrite	// 不覆盖。如果通知状态为"pending"(表示有数据未读),则此次调用xTaskNotify不做任何事,返回pdFAIL。如果通知状态不是"pending"(表示没有新数据),则通知值 = ulValue。
eSetValueWithOverwrite	// 覆盖。无论如何,不管通知状态是否为"pendng",通知值 = ulValue.

4)

/ *
该函数调用后的行为:
1)使得通知值加一
2)将对应 Task 由阻塞状态解除为非阻塞状态
*/
xTaskNotifyWait(ulBitsToClearOnEntry, /* 进入后,要清除哪些位,通知值 = 通知值 & ~(ulBitsToClearOnEntry)。
比如传入0x01,表示清除通知值的bit0;传入0xffffffff 即ULONG_MAX,表示清除所有位,即把值设置为0 */
				ulBitsToClearOnExit,  /* 退出时,要清除哪些位,通知值 = 通知值 & ~(ulBitsToClearOnExit)。
在清除某些位之前,通知值先被赋给"*pulNotificationValue"。比如入0x03,表示清除通知值的bit0、bit1;传入0xffffffff即ULONG_MAX,表示清除所有位,即把值设置为0。*/
				pulNotificationValue, /* 通知值 = 通知值 & ~(ulBitsToClearOnExit)。
在清除某些位之前,通知值先被赋给"*pulNotificationValue"。比如入0x03,表示清除通知值的bit0、bit1;传入0xffffffff即ULONG_MAX,表示清除所有位,即把值设置为0 */
				xTicksToWait)         /* 任务进入阻塞态的超时时间 */

需求及功能解析

示例演示了两组任务通知 API 的使用方法。其中 Task1 与 Task3 之间使用 Give\Tick 机制,Task2 和 Task1 之间使用 Notify\Wait 机制。

示例解析

示例输出:

This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, Minimum free heap size: 295348 bytes
TASK2: task2_flag = 0
TASK1: notify num: 1
TASK3: task3_flag = 0, ret = 1
TASK2: task2_flag = 1
TASK1: notify num: 2
TASK3: task3_flag = 1, ret = 1
TASK2: task2_flag = 2

示例中,三个任务的执行均是 Task2 驱动,只有 Task2 通知 Task1,Task1 才能解除阻塞,运行下面的代码。同理,只有 Task1 通知 Task3 ,Task3 才能解除阻塞,得到执行。因此整体的执行流为 Task2->Task1->Task3。Task1、Task3 完全是“事件”驱动的,并且在任务代码中不含任何延时,只有对应的事件触发后,才能继续向下执行。

讨论

Task Notify,即任务通知的使用方法和 API 还有很多,本小节作为入门篇简介其基本原理和用法。重要的是,读者可以理解这种事件驱动的编程思想,体会任务通知的方法和特点。对于已经熟悉 FreeRTOS 的读者还可能想了解任务通知与其他通信组件的优缺点。

Task Notifications 的优缺点

优点

  • 消息传递的更快,效率更高。
  • 每个任务创建时会自动创建该通信机制,内存消耗比其它IPC通信相比,明显少很多。

缺点

  • 只能从ISR 发送event或者data 到task, 而不能从task发送至ISR.
  • 发出的消息只能被一个task接收,但这个限制很少,因为很少有多个task从同一个通信对象获取消息。
  • 不能缓冲消息,只能保存一个值。而queue可以
  • 不能向多个task广播消息,而event group可以
  • 发送方无等待,即task Notification 不会因为taks的状态为正在阻塞而去等待发送完成后,再发送。而是会直接覆盖掉。

总结

1)FreeRTOS 提供了任务间传递信息的机制。任务可以等待一个通知信息进入阻塞状态,并在通知信息到来时自动解除阻塞,进入运行的状态。

2)任务通知是实现任务之间消息传递的机制之一,每个任务在创建时都自动地包含一个用来记录当前通知值的 uint32_t 类型的 NotifiedValue,以及一个 记录当前任务通知状态的 uint8_t 类型的 NotifyState。任务之间可以通过更改、查询 NotifiedValue 传递消息。

3)任务通知机制主要是两组 API:加减1版本的 xTaskNotifyGive\xTaskNotifyTake,操作任意值版本的 xTaskNotify\xTaskNotifyWait。

资源链接

1)Learning-FreeRTOS-with-esp32 系列博客介绍
2)对应示例的 code 链接 (点击直达代码仓库)

3)下一篇:

相关文章:

  • 建设网站公司建网页/拉新推广渠道
  • 互动营销网站建设/网络营销的四种模式
  • 中山 网站建设/网站建设品牌公司
  • 做asp网站的步骤/电商seo是指
  • wordpress 清空修订版本/搜索引擎优化的主要策略
  • 南京哪家网站做的好/免费sem工具
  • 【docker】docker的基础命令
  • 忘记密码找不回?不存在的:python自动解密解码,简直异常轻松~
  • #预处理和函数的对比以及条件编译
  • NPP净初级生产力数据获取/气象数据/太阳辐射/NDVI数据
  • 【计算机毕业设计】基于微信小程序的驾校学车预约服务系统
  • Linux技巧(六):命令尾部的作用 | 、、|、||、;、()的区别和作用(很实用)
  • asp.net设备实时管理系统VS开发sqlserver数据库web结构c#编程计算机网页项目
  • 『 云原生·Docker』Docker容器相关操作(二)
  • 04.好客租房_搭建自己的图床,接入swagger-ui,新增房源列表接口编写
  • Spring Security
  • MySql(35)索引的设计原则
  • 公众号网课搜题功能搭建