任务相关API

singlemouse 发布于 2023-08-11 1547 次阅读


内容纲要

任务相关API笔记

任务创建与删除相关API

1. 函数 xTaskCreate()

​ 此函数用于使用动态的方式创建任务,任务的任务控制块以及任务的栈空间所需的内存, 均由 FreeRTOS 从 FreeRTOS 管理的堆中分配,若使用此函数,需要在 FreeRTOSConfig.h 文件中将宏 configSUPPORT_DYNAMIC_ALLOCATION 配置为 1。此函数创建的任务会立刻进入就绪态,由任务调度器调度运行。

函数原型

BaseType_t xTaskCreate(
TaskFunction_t pxTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask
);

返回值

2. 函数 xTaskCreateStatic()

​ 此函数用于使用静态的方式创建任务,任务的任务控制块以及任务的栈空间所需的内存, 需要由用户分配提供, 若使用此函数,需 要 在 FreeRTOSConfig.h 文件中将宏 configSUPPORT_STATIC_ALLOCATION 配置为 1。此函数创建的任务会立刻进入就绪态,由任务调度器调度运行。

函数原型

TaskHandle_t xTaskCreateStatic(
TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer
);

返回值

3. 函数 xTaskCreateRestricted()

​ 此函数用于使用动态的方式创建受 MPU 保护的任务,任务的任务控制块以及任务的栈空 间所需的内存,均由 FreeRTOS 从 FreeRTOS 管理的堆中分配,若使用此函数,需要将宏 configSUPPORT_DYNAMIC_ALLOCATION 和宏 portUSING_MPU_WRAPPERS 同时配置为 1。 此函数创建的任务会立刻进入就绪态,由任务调度器调度运行。

函数原型

BaseType_t xTaskCreateRestricted(
const TaskParameters_t * const pxTaskDefinition,
TaskHandle_t * pxCreatedTask
);

返回值

4. 函数 xTaskCreateRestrictedStatic()

​ 此函数用于使用静态的方式创建受 MPU 保护的任务,此函数创建的任务的任务控制块以 及任务的栈空间所需的内存,需要由用户自行分配提供,若使用此函数,需要将宏 configSUPPORT_STATIC_ALLOCATION 和宏 portUSING_MPU_WRAPPERS 同时配置为 1。此 函数创建的任务会立刻进入就绪态,由任务调度器调度运行。

函数原型

BaseType_t xTaskCreateRestrictedStatic(
const TaskParameters_t * const pxTaskDefinition,
TaskHandle_t * pxCreatedTask
);

返回值

5. 函数 vTaskDelete()

​ 此函数用于删除已被创建的任务,被删除的任务将被从就绪态任务列表、阻塞态任务列表、 挂起态任务列表和事件列表中移除,要注意的是,空闲任务会负责释放被删除任务中由系统分 配的内存,但是由用户在任务删除前申请的内存,则需要由用户在任务被删除前提前释放,否 则将导致内存泄露。若使用此函数,需要在FreeRTOSConfig.h文件中将宏INCLUDE_vTaskDelete 配置为1。

函数原型

void vTaskDelete(TaskHandle_t xTaskToDelete);

函数 vTaskDelete()无返回值。

任务挂起与恢复相关API

1. 函数 vTaskSuspend()

​ 此函数用于挂起任务, 若使用此函数,需 要 在 FreeRTOSConfig.h 文件中将宏 INCLUDE_vTaskSuspend 配置为 1。无论优先级如何,被挂起的任务都将不再被执行,直到任务 被恢复。此函数并不支持嵌套,不论使用此函数重复挂起任务多少次,只需调用一次恢复任务 的函数,那么任务就不再被挂起。

函数原型

void vTaskSuspend(TaskHandle_t xTaskToSuspend)

函数 vTaskSuspend()无返回值。

2. 函数 vTaskResume()

​ 此函数用于在任务中恢复被挂起的任务,若使用此函数,需要在 FreeRTOSConfig.h 文件中 将宏 INCLUDE_vTaskSuspend 配置为 1。不论一个任务被函数 vTaskSuspend()挂起多少次,只 需要使用函数 vTakResume()恢复一次,就可以继续运行。

函数原型

void vTaskResume(TaskHandle_t xTaskToResume)

函数 vTaskResume()无返回值。

3. 函数 xTaskResumeFromISR()

​ 此函数用于在中断中恢复被挂起的任务,若使用此函数,需要在 FreeRTOSConfig.h 文件中 将宏 INCLUDE_xTaskResumeFromISR 配置为 1。不论一个任务被函数 vTaskSuspend()挂起多少 次,只需要使用函数 vTakResumeFromISR()恢复一次,就可以继续运行

函数原型

BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)

返回值

任务调度器的挂起和恢复

1.函数 vTaskSuspendAll()

此函数用于挂起任务调度器,当任务调度器被挂起后,就不能进行任务切换,直到任务调度器恢复运行。

void vTaskSuspendAll( void )
{
/* 未定义,不用理会 */
portSOFTWARE_BARRIER();
/* 任务调度器挂起计数器加 1 */
++uxSchedulerSuspended;
/* 未定义,不用理会 */
portMEMORY_BARRIER();
}

​ 从上面的代码可以看出,函数 vTaskSuspendAll()挂起任务调度器的操作是可以递归的,也 就是说,可以重复多次挂起任务调度器,只要后续调用相同次数的函数 xTaskResumeAll()来恢 复任务调度器运行即可。函数 vTaskSuspendAll()挂起任务调度器的操作就是将任务调度器挂起 计数器(uxSchedulerSuspended)的值加 1。在 FreeRTOS 的源码中会通过任务调度器挂起计数 器的值是否为 0,来判断任务调度器时候被挂起,如果任务调度器被挂起,FreeRTOS 就不会进 行 任 务 切 换 等 操 作。

2.函数 xTaskResumeAll()

​ 此函数用于恢复任务调度器运行,要注意的是,任务调度器的挂起是可递归的,因此需要 使用此函数恢复任务调度器与任务调度器被挂起相同的次数,才能恢复任务调度器运行。

BaseType_t xTaskResumeAll( void )
{
TCB_t * pxTCB = NULL;
BaseType_t xAlreadyYielded = pdFALSE;
/* 不会恢复没有被挂起的任务调度器
* 当 uxSchedulerSuspended 为 0 时,
* 表示任务调度器没有被挂起
*/
configASSERT( uxSchedulerSuspended );
/* 进入临界区 */
taskENTER_CRITICAL();
{
/* 任务调度器挂起计数器减 1 */
--uxSchedulerSuspended;
/* 如果任务调度器挂起计数器减到 0
* 说明任务调度器可以恢复运行了
*/
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
{
/* 任务数量计数器大于 0
* 说明系统中有任务,
* 因此需要作向相应地处理
*/
if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
{
/* 将所有挂起态任务添加到就绪态任务列表中
* 同时,如果被恢复的挂起态任务的优先级比当前运行任务的优先级高,
* 则标记需要进行任务切换
*/
while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
{
pxTCB =
listGET_OWNER_OF_HEAD_ENTRY((&xPendingReadyList));
listREMOVE_ITEM( &( pxTCB->xEventListItem ) );
portMEMORY_BARRIER();
listREMOVE_ITEM( &( pxTCB->xStateListItem ) );
prvAddTaskToReadyList( pxTCB );
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
xYieldPending = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* 如果 pxTCB 非空,
* 则表示在任务调度器挂起期间,
* 有阻塞任务超时,
* 因此需要重新计算下一个任务阻塞超时的时间
*/
if( pxTCB != NULL )
{
/* 重新计算下一个任务的阻塞超时时间 */
prvResetNextTaskUnblockTime();
}
/* 处理在任务调度器挂起期间,未处理的系统使用节拍
* 这样可以保证正确地计算阻塞任务的阻塞超时时间
* 处理方式就是调用相同次数的函数 xTaskIncrementTick()
*/
{
TickType_t xPendedCounts = xPendedTicks;
if( xPendedCounts > ( TickType_t ) 0U )
{
do
{
/* 调用函数 xTaskIncrementTick() */
if( xTaskIncrementTick() != pdFALSE )
{
xYieldPending = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
--xPendedCounts;
} while( xPendedCounts > ( TickType_t ) 0U );
xPendedTicks = 0;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* 根据需要进行任务切换 */
if( xYieldPending != pdFALSE )
{
#if ( configUSE_PREEMPTION != 0 )
{
xAlreadyYielded = pdTRUE;
}
#endif
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* 退出临界区 */
taskEXIT_CRITICAL();
return xAlreadyYielded;
}
此作者没有提供个人介绍
最后更新于 2023-08-27