描述
[另请参阅博客文章“通过 FreeRTOS 通知减少 RAM 占用空间并加速执行”]
每个 RTOS 任务都有一个任务通知数组。 每条任务通知
都有“挂起”或“非挂起”的通知状态,
以及一个 32 位通知值。 常量
configTASK_NOTIFICATION_ARRAY_ENTRIES 可设置
任务通知数组中的索引数量。 在 FreeRTOS V10.4.0 版本前,任务只有单条任务通知,
而无通知数组。
直达任务通知是直接发送至任务的事件,
而不是通过中间对象
(如队列、事件组或信号量)间接发送至任务的事件。 向任务发送“直达任务通知”
会将目标任务通知设为“挂起”状态。 正如任务可以阻塞中间对象
(如等待信号量可用的信号量),任务也可以阻塞任务通知,
以等待通知状态变为“挂起”。
向任务发送“直达任务通知”也可以
更新目标通知的值(可选),可使用下列任一方法
:
-
覆盖原值,无论接收任务是否
已读取被覆盖的值。
-
覆盖原值(仅当接收任务已读取
被覆盖的值时)。
-
在值中设置一个或多个位。
-
对值进行增量(添加 1)。
调用 xTaskNotifyWait()/xTaskNotifyWaitIndexed()
来读取通知值会将通知状态清除为“非挂起”。
此外,也可以通过调用
xTaskNotifyStateClear()/xTaskNotifyStateClearIndexed() 将通知状态明确设置为“非挂起”。
注意:数组中的每条通知均独立运行,一个任务
一次只能阻塞数组中的一条通知,且不会
被发送到任何其他数组索引的通知解除阻塞状态。
默认情况下,RTOS 任务通知功能为启用状态,并且可以
通过将
FreeRTOSConfig.h 中的 configUSE_TASK_NOTIFICATIONS 设置为 0 将其从构建中排除(每个数组索引的每个任务节省 8 字节)。
重要提示: FreeRTOS 流和消息缓冲区
使用
数组索引 0 的任务通知。 若希望保持
调用流或消息缓冲区 API 函数的任务通知,可
使用数组索引大于 0 的任务通知。
性能优势和使用限制
任务通知具有高度灵活性,使用时无需
创建单独 队列、
二进制信号量、
计数信号量
或事件组。
通过直接通知解除 RTOS 任务阻塞状态的速度和使用中间对象(如二进制信号量)相比快了 45%
*,
使用的 RAM 也更少
。
不过
这些性能优势也有一些意料之内的使用限制:
-
RTOS 任务通知仅可在只有一个任务
可以接收事件时使用。 不过,这个条件在
大多数真实世界情况下是满足的。比如,中断解除了一个任务的阻塞状态,该任务
将处理由中断接收的数据。
-
仅可在使用 RTOS 任务通知代替
队列时使用: 当某个接收任务可在阻塞状态下等待通知
(因而不花费任何 CPU 时间)时,发送任务不能
在阻塞状态下等待发送完成(在发送不能立刻完成的情况下)
。
用例
通知使用 xTaskNotifyIndexed()
和 xTaskNotifyGiveIndexed() API 函数(及其
中断安全等效物)进行发送
并保持挂起,直到接收到 RTOS 任务调用
(来自 xTaskNotifyWaitIndexed() 或
ulTaskNotifyTakeIndexed() API 函数)。
每个上述 API 函数都有一个无 "Indexed"
前缀的等效物。 非 "Indexed" 版本始终在任务通知上以
数组索引 0 运行。 例如,xTaskNotifyGive( TargetTask ) 等同于
xTaskNotifyGiveIndexed( TargetTask, 0 ),两者都在任务索引 0 处
对由以 TargetTask 为句柄的任务所引用的任务进行增量。
*
通过使用二进制信号量实现进行测量。该实现由
FreeRTOS V8.1.2 版本使用 GCC 于 -O2 优化时编译而成,未定义
configASSERT()。 仍可使用
FreeRTOS V8.2.0 和更高版本中经优化的二进制信号量实现以获得 35% 的提升。
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.