在 FreeRTOS 中,当你使用 xTaskCreate()
或其他类似函数动态创建任务时,最后一个参数是指向 TaskHandle_t
类型变量的指针。这个参数用于接收新创建任务的任务句柄(task handle)。如果你在这个参数中传递 NULL
,那么你将不会获得该任务的任务句柄。
任务句柄的作用
任务句柄是一个非常有用的工具,它允许你在之后的操作中引用特定的任务。例如:
- 删除任务:使用
vTaskDelete()
函数可以终止并删除一个任务。 - 挂起/恢复任务:使用
vTaskSuspend()
和vTaskResume()
可以控制任务的执行状态。 - 更改任务优先级:使用
vTaskPrioritySet()
可以调整任务的优先级。 - 发送通知给任务:使用
xTaskNotifyGive()
等函数可以向任务发送通知。
当传递 NULL
作为任务句柄参数时
如果你在调用 xTaskCreate()
时传递 NULL
作为最后一个参数,那么虽然任务仍然会被成功创建并且可以正常运行,但你将无法通过任务句柄直接对该任务进行上述操作。这并不意味着任务没有句柄——FreeRTOS 内部仍然会为每个任务维护一个句柄,只是你无法从外部获取和使用它。
示例代码
BaseType_t xReturned;
// 创建任务并获取任务句柄
xReturned = xTaskCreate(
vTaskCode, // 任务函数
"TaskName", // 任务名称
STACK_SIZE, // 栈大小
(void *)param, // 传递给任务函数的参数
tskIDLE_PRIORITY + 1,// 任务优先级
&xHandle); // 任务句柄指针
if (xReturned == pdPASS)
{
// 任务创建成功,并且可以通过 xHandle 操作任务
}
// 创建任务但不获取任务句柄
xReturned = xTaskCreate(
vTaskCode, // 任务函数
"TaskName", // 任务名称
STACK_SIZE, // 栈大小
(void *)param, // 传递给任务函数的参数
tskIDLE_PRIORITY + 1,// 任务优先级
NULL); // 不需要任务句柄
if (xReturned == pdPASS)
{
// 任务创建成功,但没有保存任务句柄
}
总结
- 传递非
NULL
的任务句柄指针:你可以稍后使用该句柄来管理和控制任务。 - 传递
NULL
:任务仍然会被创建并运行,但你将无法通过任务句柄对其进行管理。
因此,是否需要传递 NULL
取决于你是否计划在未来对任务进行额外的操作。如果你不需要这些功能,传递 NULL
是完全可以接受的做法;否则,建议保留任务句柄以便后续使用。
如果再用xTaskGetCurrentTaskHandle()能获取到句柄吗
xTaskGetCurrentTaskHandle()
函数用于获取当前正在执行的任务的句柄。如果你在任务内部调用这个函数,它将返回该任务自己的任务句柄。因此,即使你在创建任务时没有通过 xTaskCreate()
的最后一个参数保存任务句柄(即传递了 NULL
),你仍然可以在任务内部使用 xTaskGetCurrentTaskHandle()
来获取其自身的句柄。
使用场景
-
任务自我管理:如果一个任务需要对自己进行某些操作(如挂起自己、改变自己的优先级等),它可以使用
xTaskGetCurrentTaskHandle()
来获得自己的句柄。 -
外部任务管理:对于那些需要从外部管理的任务,最好是在创建时就保存它们的句柄。然而,如果某个任务偶尔需要从外部被管理,并且你不希望总是传递和保存它的句柄,那么可以让该任务在需要的时候调用
xTaskGetCurrentTaskHandle()
并将其句柄发送给另一个任务或存储在一个全局变量中。
示例代码
假设我们有一个任务 task1
,它在创建时没有保存任务句柄(即传递了 NULL
)。我们可以在任务内部获取并打印其句柄:
void task1(void *pvParameters)
{
TaskHandle_t xTaskHandle;
// 获取当前任务的句柄
xTaskHandle = xTaskGetCurrentTaskHandle();
// 打印任务句柄(注意:具体的打印格式取决于你的调试环境)
printf("Task1 handle is %p\r\n", xTaskHandle);
while (1)
{
// 任务逻辑...
vTaskDelay(pdMS_TO_TICKS(1000)); // 每秒延迟一次
}
}
void freertos_start(void)
{
BaseType_t xReturned;
/* 创建任务但不获取任务句柄 */
xReturned = xTaskCreate(
task1,
"task1",
TASK1_STACK_SIZE,
NULL,
TASK1_PRIORITY,
NULL); // 不保存任务句柄
if (xReturned != pdPASS)
{
// 处理任务创建失败的情况
printf("Failed to create task1.\r\n");
while (1);
}
/* 启动调度器 */
vTaskStartScheduler();
}
在这个例子中,尽管我们在创建 task1
时没有保存它的句柄,但它仍然能够在运行时通过 xTaskGetCurrentTaskHandle()
获取到自己的句柄。
注意事项
-
只能获取当前任务的句柄:
xTaskGetCurrentTaskHandle()
只能用于获取调用此函数的任务的句柄。如果你想从其他任务或中断上下文中获取不同任务的句柄,则必须在创建这些任务时保存它们的句柄。 -
线程安全性:由于
xTaskGetCurrentTaskHandle()
是在任务上下文中调用的,因此它是线程安全的,不会引起竞争条件。
总结
- 如果你需要从任务内部管理自身,可以使用
xTaskGetCurrentTaskHandle()
来获取当前任务的句柄。 - 对于需要从外部管理的任务,建议在创建时保存它们的句柄以供后续使用。