在 FreeRTOS 中,任务的 挂起(Suspend) 和 恢复(Resume) 是常用的任务控制机制,用于临时停止和重新启动任务。以下是详细的使用方法及示例代码(C语言)。
1. 任务挂起(Suspend)
挂起任务会使其停止运行,但仍然占用内存资源,直到被恢复。
API 函数
void vTaskSuspend(TaskHandle_t xTaskToSuspend);
-
参数:
-
xTaskToSuspend
:要挂起的任务的句柄(TaskHandle_t
),如果传入NULL
,则挂起 当前任务。
-
示例:挂起任务
#include "FreeRTOS.h"
#include "task.h"
TaskHandle_t xTask1Handle = NULL; // 任务句柄
void Task1(void *pvParameters) {
while(1) {
printf("Task1 is running...\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void Task2(void *pvParameters) {
while(1) {
printf("Task2 is running...\n");
vTaskDelay(2000 / portTICK_PERIOD_MS);
// 挂起 Task1
printf("Suspending Task1...\n");
vTaskSuspend(xTask1Handle);
vTaskDelay(5000 / portTICK_PERIOD_MS); // 等待 5 秒
// 恢复 Task1
printf("Resuming Task1...\n");
vTaskResume(xTask1Handle);
}
}
int main() {
// 创建任务
xTaskCreate(Task1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);
xTaskCreate(Task2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
// 启动调度器
vTaskStartScheduler();
while(1);
return 0;
}
运行结果:
Task1 is running...
Task2 is running...
Task1 is running...
Task2 is running...
Suspending Task1... (Task1 被挂起,不再输出)
Task2 is running...
Task2 is running...
Resuming Task1... (Task1 恢复运行)
Task1 is running...
Task2 is running...
...
2. 任务恢复(Resume)
恢复被挂起的任务,使其重新进入就绪状态,等待调度。
API 函数
void vTaskResume(TaskHandle_t xTaskToResume);
-
参数:
-
xTaskToResume
:要恢复的任务句柄(TaskHandle_t
)。
-
示例:恢复任务
见上面的 Task2
示例,vTaskResume(xTask1Handle)
恢复 Task1
。
3. 从 ISR(中断)中恢复任务
如果需要在 中断服务程序(ISR) 中恢复任务,必须使用 带 FromISR 的 API:
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume);
-
参数:
-
xTaskToResume
:要恢复的任务句柄。
-
-
返回值:
-
pdTRUE
:恢复任务导致更高优先级任务就绪,可能需要手动触发任务切换(portYIELD_FROM_ISR()
)。 -
pdFALSE
:没有触发更高优先级任务切换。
-
示例:在中断中恢复任务
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
TaskHandle_t xTask1Handle = NULL;
void Task1(void *pvParameters) {
while(1) {
printf("Task1 is running...\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
// 模拟中断服务程序(ISR)
void Some_IRQ_Handler(void) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// 从 ISR 恢复 Task1
xTaskResumeFromISR(xTask1Handle);
// 如果需要,手动触发任务切换
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
int main() {
xTaskCreate(Task1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);
vTaskStartScheduler();
while(1);
return 0;
}
4. 挂起所有任务(挂起调度器)
如果需要临时挂起 所有任务(但不挂起调度器本身),可以使用:
void vTaskSuspendAll(void); // 挂起所有任务
BaseType_t xTaskResumeAll(void); // 恢复所有任务
适用场景:
-
在 非任务环境(如初始化代码)中临时禁止任务调度。
-
执行 关键代码段,避免被其他任务打断。
示例:挂起所有任务
void CriticalFunction(void) {
vTaskSuspendAll(); // 禁止任务调度
// 执行关键操作(不会被其他任务打断)
SomeCriticalOperation();
xTaskResumeAll(); // 恢复任务调度
}
5. 注意事项
-
任务挂起不会释放内存,只是暂停执行。
-
不能挂起空闲任务(Idle Task),否则可能导致系统死锁。
-
中断中恢复任务 必须使用
xTaskResumeFromISR
,不能直接调用vTaskResume
。 -
避免频繁挂起/恢复,可能影响实时性。
总结
操作 | API | 适用场景 |
---|---|---|
挂起任务 | vTaskSuspend() | 临时停止某个任务 |
恢复任务 | vTaskResume() | 恢复被挂起的任务 |
中断中恢复任务 | xTaskResumeFromISR() | 在 ISR 中恢复任务 |
挂起所有任务 | vTaskSuspendAll() | 禁止任务调度(关键代码段) |
恢复所有任务 | xTaskResumeAll() | 恢复任务调度 |