任务相关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; }
Comments NOTHING