任务相关API

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


Table of Contents

任务相关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