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