|
|
@@ -34,12 +34,14 @@ FreeRTOS 已经有队列、信号量、事件标志组这些 IPC 机制,为什
|
|
|
**⚠ 注意:`xTaskNotifyGive()` 的本质**:查看源码发现 `xTaskNotifyGive()` 其实是一个**宏**,展开后等价于 `xTaskNotify(xTaskToNotify, 0, eIncrement)`。也就是说"信号量模式"在底层和"消息邮箱/事件组模式"使用的是同一个 `xTaskNotify()` 函数,只是 `eAction` 参数不同。三种模式的发送端完全可以统一理解为"调用 xTaskNotify 配上不同的 eAction 参数"。
|
|
|
|
|
|
**普通 IPC 的通信路径**:
|
|
|
+
|
|
|
```
|
|
|
任务 A → [创建队列/信号量对象] → 放入数据 → 队列/信号量 → 任务 B 取出数据
|
|
|
└── 中间对象(额外分配内存)──┘
|
|
|
```
|
|
|
|
|
|
**任务通知的通信路径**:
|
|
|
+
|
|
|
```
|
|
|
任务 A → 直接写入任务 B 的 TCB
|
|
|
└── 不创建任何对象 ──┘
|
|
|
@@ -61,39 +63,40 @@ FreeRTOS 已经有队列、信号量、事件标志组这些 IPC 机制,为什
|
|
|
|
|
|
通知值的 32 位可以灵活解释,由此衍生出三种使用模式,替代三种传统 IPC:
|
|
|
|
|
|
-| 模式 | 对应传统 IPC | 发送函数 | 接收函数 | 32 位值的用法 |
|
|
|
-|------|-------------|---------|---------|--------------|
|
|
|
-| **信号量模式** | 二值/计数信号量 | `xTaskNotifyGive()` | `ulTaskNotifyTake()` | 当作计数器:Give 加 1,Take 减 1 |
|
|
|
-| **消息邮箱模式** | 队列(单消息) | `xTaskNotify(..., eSetValueWithOverwrite)` | `xTaskNotifyWait()` | 当作消息容器:覆写/条件覆写 32 位值 |
|
|
|
-| **事件标志组模式** | 事件标志组 | `xTaskNotify(..., eSetBits)` | `xTaskNotifyWait()` | 当作位图:按位 OR 设置标志位 |
|
|
|
+| 模式 | 对应传统 IPC | 发送函数 | 接收函数 | 32 位值的用法 |
|
|
|
+| ------------------------ | --------------- | -------------------------------------------- | ---------------------- | ----------------------------------- |
|
|
|
+| **信号量模式** | 二值/计数信号量 | `xTaskNotifyGive()` | `ulTaskNotifyTake()` | 当作计数器:Give 加 1,Take 减 1 |
|
|
|
+| **消息邮箱模式** | 队列(单消息) | `xTaskNotify(..., eSetValueWithOverwrite)` | `xTaskNotifyWait()` | 当作消息容器:覆写/条件覆写 32 位值 |
|
|
|
+| **事件标志组模式** | 事件标志组 | `xTaskNotify(..., eSetBits)` | `xTaskNotifyWait()` | 当作位图:按位 OR 设置标志位 |
|
|
|
|
|
|
**一句话选型**:
|
|
|
+
|
|
|
- 只需通知对方"事件发生了" → 信号量模式(最轻量)
|
|
|
- 需要传递一个数值给对方 → 消息邮箱模式
|
|
|
- 需要多个条件的组合触发 → 事件标志组模式
|
|
|
|
|
|
### 核心劣势(与传统 IPC 对比)
|
|
|
|
|
|
-| 对比项 | 队列/信号量/事件组 | 任务通知 |
|
|
|
-|--------|-------------------|---------|
|
|
|
-| 通信方向 | 多对多(多个任务可发/收) | 只能一对一(一个任务只有一个通知值) |
|
|
|
-| 数据缓存 | 队列可缓存多条消息 | 只能缓存一个 32 位值(覆写会丢数据) |
|
|
|
-| ISR 接收 | 可接收 | **不能接收**(无 FromISR 版本接收函数) |
|
|
|
-| 创建步骤 | 需先 Create 对象 | **无需创建**,直接用 |
|
|
|
+| 对比项 | 队列/信号量/事件组 | 任务通知 |
|
|
|
+| -------- | ------------------------- | --------------------------------------------- |
|
|
|
+| 通信方向 | 多对多(多个任务可发/收) | 只能一对一(一个任务只有一个通知值) |
|
|
|
+| 数据缓存 | 队列可缓存多条消息 | 只能缓存一个 32 位值(覆写会丢数据) |
|
|
|
+| ISR 接收 | 可接收 | **不能接收**(无 FromISR 版本接收函数) |
|
|
|
+| 创建步骤 | 需先 Create 对象 | **无需创建**,直接用 |
|
|
|
|
|
|
### 核心API
|
|
|
|
|
|
-| 函数 | 参数 | 功能简述 |
|
|
|
-|------|------|---------|
|
|
|
-| `xTaskNotifyGive()` | `xTaskToNotify` | 发送通知(信号量模式),通知值 +1 |
|
|
|
-| `ulTaskNotifyTake()` | `xClearCountOnExit`, `xTicksToWait` | 接收通知(信号量模式),返回通知值 |
|
|
|
-| `xTaskNotify()` | `xTaskToNotify`, `ulValue`, `eAction` | 发送通知(带值),eAction 控制写/OR/覆写行为 |
|
|
|
-| `xTaskNotifyWait()` | `ulBitsToClearOnEntry`, `ulBitsToClearOnExit`, `pulNotificationValue`, `xTicksToWait` | 接收通知(带值),可获取通知值和清除指定位 |
|
|
|
-| `xTaskNotifyIndexed()` | `xTaskToNotify, uxIndex, ulValue, eAction` | 写目标任务通知数组指定元素 |
|
|
|
-| `xTaskNotifyWaitIndexed()` | `uxIndex, ...` | 阻塞读本任务通知数组指定元素 |
|
|
|
-| `ulTaskNotifyTakeIndexed()` | `uxIndex, ...` | 信号量模式取通知数组指定元素 |
|
|
|
-| `xTaskNotifyFromISR()` | 同上+ISR 版本 | 中断中发送通知 |
|
|
|
-| `vTaskNotifyGiveFromISR()` | `xTaskToNotify`, `pxHigherPriorityTaskWoken` | 中断中发送(信号量模式) |
|
|
|
+| 函数 | 参数 | 功能简述 |
|
|
|
+| ----------------------------- | --------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
|
|
+| `xTaskNotifyGive()` | `xTaskToNotify` | 发送通知(信号量模式),通知值 +1 |
|
|
|
+| `ulTaskNotifyTake()` | `xClearCountOnExit`, `xTicksToWait` | 接收通知(信号量模式),返回通知值 |
|
|
|
+| `xTaskNotify()` | `xTaskToNotify`, `ulValue`, `eAction` | 发送通知(带值),eAction 控制写/OR/覆写行为 |
|
|
|
+| `xTaskNotifyWait()` | `ulBitsToClearOnEntry`, `ulBitsToClearOnExit`, `pulNotificationValue`, `xTicksToWait` | 接收通知(带值),可获取通知值和清除指定位 |
|
|
|
+| `xTaskNotifyIndexed()` | `xTaskToNotify, uxIndex, ulValue, eAction` | 写目标任务通知数组指定元素 |
|
|
|
+| `xTaskNotifyWaitIndexed()` | `uxIndex, ...` | 阻塞读本任务通知数组指定元素 |
|
|
|
+| `ulTaskNotifyTakeIndexed()` | `uxIndex, ...` | 信号量模式取通知数组指定元素 |
|
|
|
+| `xTaskNotifyFromISR()` | 同上+ISR 版本 | 中断中发送通知 |
|
|
|
+| `vTaskNotifyGiveFromISR()` | `xTaskToNotify`, `pxHigherPriorityTaskWoken` | 中断中发送(信号量模式) |
|
|
|
|
|
|
## 实验
|
|
|
|
|
|
@@ -398,7 +401,7 @@ void task3(void *const pvParameters)
|
|
|
|
|
|
## 常见问题与避坑
|
|
|
|
|
|
-1. **任务通知只能一对一**:一个任务只有一个通知值。不能像事件标志组那样多个任务等待同一个事件。
|
|
|
+1. **任务通知只能一对一**:v10.4 之前一个任务只有一个通知值。不能像事件标志组那样多个任务等待同一个事件。
|
|
|
2. **ISR 不可接收通知**:没有 `xTaskNotifyWaitFromISR()` 函数。接收任务通知只能在任务上下文中进行。
|
|
|
3. **通知值溢出不提示**:`xTaskNotifyGive()` 使 32 位通知值递增,溢出后归零且无错误提示。
|
|
|
4. **信号量模式的 xClearCountOnExit**:
|