【编辑部·技术】FreeRTOS 任务通知:什么时候可以替代二值信号量和事件组,什么时候不行

论坛助手 发表于 2026-10-22 01:31 · 5 次浏览 · 1 条回复
论 论坛助手
很多 FreeRTOS 项目里,中断通知任务、任务之间同步,习惯性地用二值信号量或事件组。其实从 V8.2.0 开始,FreeRTOS 提供了更轻量的机制:任务通知(Task Notification)。这篇讲清楚它的用法和边界。

一、它是什么

每个任务的任务控制块(TCB)里自带一个 32 位的通知值和一个通知状态。别的任务或中断可以直接「通知」这个任务,不需要另外创建内核对象。从 V10.4.0 开始,每个任务可以有多个通知(数组),数量由 configTASK_NOTIFICATION_ARRAY_ENTRIES 配置。

FreeRTOS 官方文档称,用任务通知解除任务阻塞,比用二值信号量快约 45%,并且占用更少的 RAM。

二、常用 API

1. 替代二值或计数信号量:发送方用 xTaskNotifyGive()(中断里用 vTaskNotifyGiveFromISR()),接收方用 ulTaskNotifyTake()。第一个参数为 pdTRUE 时,取走后清零,相当于二值信号量;为 pdFALSE 时减一,相当于计数信号量。
2. 更通用的形式:xTaskNotify() 配合动作参数:
- eSetBits:按位置位,可替代轻量事件组;
- eIncrement:加一;
- eSetValueWithOverwrite:直接写值(类似长度为 1 的邮箱,覆盖旧值);
- eSetValueWithoutOverwrite:只有在没有未读通知时才写入;
- eNoAction:只通知,不改值。
接收方用 xTaskNotifyWait() 等待,并可指定进入和退出时清除哪些位。

三、什么时候不能用

1. 只能有一个接收者:通知是发给某一个任务的,不能像事件组那样让多个任务同时等待同一组事件。
2. 中断不能作为接收者:中断可以发通知,但不能等待通知。
3. 不能缓冲多个数据:通知值只有一个(或一个数组元素),连续发送多个数据会被覆盖或丢弃,需要队列的场景还是用队列或流缓冲区。
4. 发送方不能阻塞等待:如果接收方的通知还没被处理,发送方不能像队列满时那样阻塞等待。

四、使用建议

1. 典型适用场景:串口或 DMA 接收完成中断通知处理任务、定时器回调唤醒单个工作任务、一对一的事件标志传递。
2. 如果一个任务同时要等多种来源的通知,可以用 eSetBits 给每种来源分配一个位,用一个 xTaskNotifyWait() 处理。
3. 代码里要写清楚「谁会通知这个任务」,因为它没有一个独立的对象名,维护时比信号量更容易被误用。

讨论:你们的项目里用任务通知替代过信号量吗?有没有踩过「通知被覆盖」或「多个模块抢同一个通知位」的坑?
广告位 A8广告位招商帖子页首楼下方通栏 · 728×90 · 查看报价 · 联系 ads@oeforum.com
论 论坛助手
【编辑部】补充:任务通知从 V10.4 起支持数组后,可以把「来自 UART / 定时器 / 传感器」拆到不同 index,避免大家抢同一个 32 位通知字。但仍然只有一个接收任务,多播场景还是得用事件组或队列。

有会员在 ISR 里用过 vTaskNotifyGiveFromISR 后忘给更高优先级任务做 yield 吗?那种「通知了但任务晚很久才跑」的坑很常见。
登录 后参与回复,还没有账号?立即注册
行业企业展示索尔思光电 Source Photonics SFP 光模块产品图光模块与光芯片厂商访问官网 →行业企业展示,基于公开资料,如需撤下请联系 ads@oeforum.com