1. 任务通知的概念
FreeRTOS 从 V8.2.0 版本开始引入了任务通知功能。每个任务都有一个 32 位的通知值,任务通知可以替代二值信号量、计数信号量、事件组,甚至可以替代长度为 1 的队列(用于传递一个 32 位整数或指针值)。相比传统的通信方式,任务通知更加高效、节省内存空间,并且不需要创建额外的通信对象(如信号量或队列)。
2. 任务通知的优点
- 性能优势:使用任务通知解除阻塞的任务比使用信号量等传统通信方式快约 45%。
- 内存节省:不需要为任务通知创建额外的信号量、队列等,节省了 RAM 内存空间。
- 简化设计:任务通知的使用更加简单直接,不需要创建复杂的通信对象。
3. 任务通知的使用
要使用任务通知,需要在 FreeRTOSConfig.h
文件中将宏 configUSE_TASK_NOTIFICATIONS
设置为 1。通常情况下,该宏默认是启用的。
任务通知有以下几种发送方式:
- 发送通知,不覆盖未读通知值
- 如果任务已有未读的通知值,新通知不会覆盖旧的通知值。
- 发送通知,直接覆盖通知值
- 无论任务是否有未读通知值,新的通知值将直接覆盖旧值。
- 发送通知,设置通知值的某些位
- 可以通过设置通知值的某些位来使用通知值作为事件组。
- 发送通知,递增通知值
- 可以通过递增通知值的方式将其用作计数信号量。
4. 任务通知的API函数
1. xTaskNotify()
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction );
- xTaskToNotify:要通知的任务句柄。
- ulValue:通知值。
- eAction:指定通知方式,可以是以下之一:
eSetBits
:设置通知值的某些位(可以将通知用作事件组)。eIncrement
:递增通知值(可以将通知用作计数信号量)。eSetValueWithOverwrite
:直接覆盖通知值。eSetValueWithoutOverwrite
:如果已有未读通知值,则不覆盖。
2. xTaskNotifyGive()
void xTaskNotifyGive( TaskHandle_t xTaskToNotify );
- xTaskToNotify:要通知的任务句柄。该函数是
xTaskNotify()
的简化形式,用于递增通知值。
3. ulTaskNotifyTake()
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
- xClearCountOnExit:指定是否在退出时清除通知值。
- xTicksToWait:等待通知的时间。
4. xTaskNotifyWait()
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t *pulNotificationValue,
TickType_t xTicksToWait );
- ulBitsToClearOnEntry:在进入函数时清除的通知值的某些位。
- ulBitsToClearOnExit:在退出函数时清除的通知值的某些位。
- pulNotificationValue:指向通知值的指针。
- xTicksToWait:等待通知的时间。
5. 任务通知的使用示例
以下是一个使用任务通知的简单示例,演示了如何使用任务通知来替代信号量。
// 任务 A:等待任务 B 发送通知
void TaskA(void *pvParameters) {
uint32_t ulNotificationValue;
for (;;) {
// 等待通知,不清除位,并指定最大等待时间
ulNotificationValue = ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
if (ulNotificationValue > 0) {
// 执行接收到通知后的操作
}
}
}
// 任务 B:发送通知给任务 A
void TaskB(void *pvParameters) {
for (;;) {
// 执行任务 B 的一些操作
// 发送通知给任务 A,使用递增通知值方式
xTaskNotifyGive(xTaskAHandle);
// 等待下一次通知
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
6. 任务通知的局限性
虽然任务通知具有显著的优点,但也有以下限制:
- 单任务接收:任务通知只能由一个指定任务接收,不能用于多个任务的同步。
- 发送任务不会阻塞:发送通知的任务不会因为发送失败而阻塞。
7. 总结
任务通知为 FreeRTOS 提供了一种高效、灵活的任务间通信方式,可以替代传统的信号量、队列等机制。在需要高效通信且只涉及单一任务的场景下,任务通知是一个理想的选择。然而,对于需要多个任务同步的场景,传统的 IPC 机制仍然有其独特的优势。
欢迎指出博客中的错误,如果你觉得对你有用,记得点赞三连,有问题可留言,会及时回复