任务创建/删除流程
1.简介
FreeRTOS 中任务创建通过 xTaskCreate() 或 xTaskCreateStatic() 实现。动态创建(xTaskCreate)会自动分配任务栈和TCB(任务控制块),静态创建(xTaskCreateStatic)需用户预分配内存。
动态创建流程:
- 参数校验:检查栈深度、任务函数指针等有效性。
- 内存分配:调用
pvPortMalloc分配TCB和栈空间。 - TCB初始化:填充任务名、优先级、栈指针等字段。
- 栈初始化:调用
pxPortInitialiseStack模拟中断压栈,构造初始上下文。 - 任务就绪:将任务加入就绪列表,触发调度(若调度已启动)。
任务删除流程:任务删除通过 vTaskDelete() 实现,支持删除其他任务或自身(传参 NULL)。删除后资源需由空闲任务回收。
核心步骤:
- 任务状态检查:若删除自身标记为待删除状态并触发调度;否则直接从就绪/阻塞列表移除。
- 资源释放:TCB和栈内存由空闲任务通过
prvDeleteTCB()释放。 - 调度触发:若删除高优先级任务,可能引发上下文切换。
2.任务控制块/链表项:
typedef struct tskTaskControlBlock
{
volatile StackType_t * pxTopOfStack;
#if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xMPUSettings;
#endif
ListItem_t xStateListItem; //链表项,后面会加入任务的状态链表
ListItem_t xEventListItem; //链表项,后页面会加入信号量,消息队列等链表
UBaseType_t uxPriority; //任务优先级
StackType_t * pxStack; //任务栈的起点
char pcTaskName[ configMAX_TASK_NAME_LEN ]; //任务名,可以为空吧
#if ( configUSE_TRACE_FACILITY == 1 ) //trace时使用
UBaseType_t uxTCBNumber;
UBaseType_t uxTaskNumber;
#endif
#if ( configUSE_MUTEXES == 1 ) //互斥时使用--初始优先级和继承优先级
UBaseType_t uxBasePriority;
UBaseType_t uxMutexesHeld;
#endif
#if ( configUSE_TASK_NOTIFICATIONS == 1 ) //任务通知使用--存放任务通知的值和状态
volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
#endif
} tskTCB;
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
configLIST_VOLATILE TickType_t xItemValue; //链表值,用于链表排序
struct xLIST_ITEM * configLIST_VOLATILE pxNext; //指向后一个链表项
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; //指向前一个链表项
void * pvOwner; //一般用于存放TCB指针
struct xLIST * configLIST_VOLATILE pxContainer; //用于存包含此链表项的链表的指针
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
};
3.任务创建/删除(下文只分析动态创建的):
为什么推荐使用动态创建:
- 我是用的芯片为f407,ram空间为:192K的----包括64K的CCM(仅CPU可访问)、112K的SRAM1(主RAM)和16K的SRAM2(外设使用)。空间足够大可以直接用heap4管理。
- heap4提供了空间管理回收,若是自己分配还需要自己释放,检查是否溢出
/***************************************************************
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, //回调函数名/地址
const char * const pcName, //任务名字
const configSTACK_DEPTH_TYPE usStackDepth, //任务栈大小,单位4byte
void * const pvParameters, //回调函形参
UBaseType_t uxPriority, //任务优先级,数值越大,优先级越高
TaskHandle_t * const pxCreatedTask ) //任务控制块地址/句柄
********************************************************************/
代码分析:
1.xTaskCreate
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 )
{
TCB_t * pxNewTCB;
BaseType_t xReturn;
#if ( portSTACK_GROWTH > 0 ) //增栈
{
************************************
}
#else //减栈
{
StackType_t * pxStack;
/*-------------------------申请任务栈空间-----------------------*/
pxStack = pvPortMallocStack((((size_t)usStackDepth)*sizeof( StackType_t ) ) );
if( pxStack != NULL ) //如果申请栈空间成功
{ /*---------------------申请TCB空间-------------------*/
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL ) //如果TCB空间申请成功
{
memset((void*)pxNewTCB,0x00,sizeof(TCB_t)); //清空TCB空间
pxNewTCB->pxStack = pxStack; //TCB->pxStack初始化
}
else {vPortFreeStack( pxStack );} //申请TCB空间失败
}
else pxNewTCB = NULL; //申请任务栈空间失败
}
#endif /* portSTACK_GROWTH */
if(pxNewTCB != NULL) //TCB和栈空间都申请成功
{
prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); //初始化任务TCB以及栈
prvAddNewTaskToReadyList( pxNewTCB ); //将任务添加到就绪链表
xReturn = pdPASS;
}
else xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; //申请空间失败
return xReturn; //返回
}
/*------------------------------------------------------------------------------------*/
1.1调用函数分析:
prvInitialiseNewTask()
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask,
TCB_t * pxNewTCB,
const MemoryRegion_t * const xRegions )
{
StackType_t * pxTopOfStack;
UBaseType_t x;
/*------------------------初始化任务栈,每byte都为0xa5,检查栈溢出使用----------------------*/
#if ( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 )
{
(void)memset(pxNewTCB->pxStack,(int)tskSTACK_FILL_BYTE,(size_t)ulStackDepth * sizeof(StackType_t));
}
#endif
/*------------------------------------------------------------------------------------*/
/*------------------如果是满减栈:找出栈顶位置(高地址),对齐-------------------------------*/
#if ( portSTACK_GROWTH < 0 )
{
pxTopOfStack = &(pxNewTCB->pxStack[ulStackDepth-(uint32_t)1]);
pxTopOfStack = (StackType_t *)(((portPOINTER_SIZE_TYPE)pxTopOfStack)&(~(( portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
configASSERT(((portPOINTER_SIZE_TYPE)pxTopOfStack&(portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK)==0UL));
}
#else /* portSTACK_GROWTH */
*****************************
#endif /* portSTACK_GROWTH */
/*-----------------------------------------------------------------------------------*/
/*-------------------如果任务名不为NULL,TCB->pcTaskName初始化--------------------------*/
if( pcName != NULL )
{
for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
{
pxNewTCB->pcTaskName[ x ] = pcName[ x ];
if( pcName[ x ] == ( char ) 0x00 )
{
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/*----------------------------------------------------------------------------------*/
/*------------任务优先级设置:如果任务优先级大于最大优先级,设置为最大优先级
configASSERT( uxPriority < configMAX_PRIORITIES );
if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
{
uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxNewTCB->uxPriority = uxPriority;
/*----------------------------------------------------------------------------------*/
/*--------------------------如果设置了互斥,记录原优先级-------------------------------*/
#if ( configUSE_MUTEXES == 1 )
{
pxNewTCB->uxBasePriority = uxPriority;
}
#endif /* configUSE_MUTEXES */
/*---------------------------------------------------------------------------------*/
/*------------链表项初始化,清除链表项中pxContainer,表示未加入任何链表------------------*/
vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
/*---------------------------------------------------------------------------------*/
/*将TCB指针放入链表项StateListItem,EventListItem,优先级和最高优先级的差放入xEventListItem-*/
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority );
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
/*---------------------------------------------------------------------------------*/
#if ( portUSING_MPU_WRAPPERS == 1 )
{
**********************************
}
#else ( void ) xRegions;
#endif
/*--------------------------------TCB初始化-------------------------------------*/
#if ( portUSING_MPU_WRAPPERS == 1 )
{
********************************
}
#else /* portUSING_MPU_WRAPPERS */
{
#if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )
{
****************************************
}
#else //获取栈顶
{
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
}
#endif /* portHAS_STACK_OVERFLOW_CHECKING */
}
#endif
/*----------------------------TCB地址存入pxCreatedTask--------------------------*/
if( pxCreatedTask != NULL )
{
*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*------------------------------------------------------------------------------------*/
prvAddNewTaskToReadyList( )
static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB )
{
taskENTER_CRITICAL(); //进入临界缓冲区
{
uxCurrentNumberOfTasks++;
/*-----------------------------------如果当前没有任务-----------------------------------*/
if( pxCurrentTCB == NULL )
{
pxCurrentTCB = pxNewTCB;
if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ) //如果这是第一个任务
{
prvInitialiseTaskLists();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*---------------------------------------当前有的任务-----------------------------------*/
else
{
if( xSchedulerRunning == pdFALSE ) //如果没有开启调度
{
/*--如果新任务优先级高于或者等于当前任务,当前任务设置为新任务--*/
if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
{
pxCurrentTCB = pxNewTCB;
}
else mtCOVERAGE_TEST_MARKER();
}
else //如果开启调度,不需要更换当前任务
{
mtCOVERAGE_TEST_MARKER();
}
}
uxTaskNumber++; //统计任务数量
#if ( configUSE_TRACE_FACILITY == 1 )
{
pxNewTCB->uxTCBNumber = uxTaskNumber; //TCB中记录自己序号
}
#endif /* configUSE_TRACE_FACILITY */
traceTASK_CREATE( pxNewTCB );
prvAddTaskToReadyList( pxNewTCB );
portSETUP_TCB( pxNewTCB );
}
taskEXIT_CRITICAL(); //退出临界缓冲区
if( xSchedulerRunning != pdFALSE ) //如果调度开启
{
if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority ) //新加入任务优先级高
{
taskYIELD_IF_USING_PREEMPTION(); //唤醒任务切换-唤醒pendsv中断
}
else //新任务优先级低,不理会
{
mtCOVERAGE_TEST_MARKER();
}
}
else //如果任务调度没开启,不予理会
{
mtCOVERAGE_TEST_MARKER();
}
}
/*-----------------------------------------------------------*/
代码片段:
void vTaskDelete( TaskHandle_t xTaskToDelete ) {
TCB_t *pxTCB;
// 获取待删除任务的TCB
pxTCB = prvGetTCBFromHandle( xTaskToDelete );
// 从状态列表中移除
uxListRemove( &( pxTCB->xStateListItem ) );
// 如果是删除自身,标记为待删除并触发调度
if( xTaskToDelete == NULL ) {
vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
portYIELD();
} else {
prvDeleteTCB( pxTCB );
}
}
2.xTaskCreate()
void vTaskDelete( TaskHandle_t xTaskToDelete )
{
TCB_t * pxTCB;
taskENTER_CRITICAL(); //进入临界区
{
pxTCB = prvGetTCBFromHandle( xTaskToDelete ); //判断删除自身还是别的任务
/*------------------------------将任务从其状态链表中移除------------------------------*/
if( uxListRemove(&(pxTCB->xStateListItem))==(UBaseType_t)0)
{
taskRESET_READY_PRIORITY( pxTCB->uxPriority ); //将其从就绪链表中移除
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/*--------------------------------如果任务在等待事件---------------------------------*/
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
( void ) uxListRemove( &( pxTCB->xEventListItem ) ); //将事件从其链表中移除
}
else
{
mtCOVERAGE_TEST_MARKER();
}
uxTaskNumber++; //任务数量依旧增加
/*--------------------------------如果待删除任务是当前任务---------------------------*/
if( pxTCB == pxCurrentTCB )
{
/*-------任务放入终止链表中,后续在idle任务中删除--------*/
vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
/*----增加此值,目的是idle任务可以知道有任务需要删除-----*/
++uxDeletedTasksWaitingCleanUp;
/*---window模式使用,arm不用理会----*/
traceTASK_DELETE( pxTCB );
portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
}
/*-------------------------------如果待删除任务不是当前任务---------------------------*/
else
{
--uxCurrentNumberOfTasks; //减少当前任务数量
traceTASK_DELETE( pxTCB );
prvResetNextTaskUnblockTime(); //重置解除阻塞时间
}
}
taskEXIT_CRITICAL(); //退出临界保护
/*----------------如果要删除的任务不是当前任务,直接删除TCB,释放空间--------------------*/
if( pxTCB != pxCurrentTCB )
{
prvDeleteTCB( pxTCB );
}
/*----------------------------如果调度器重新开始计时调度-----------------------------*/
if( xSchedulerRunning != pdFALSE )
{
if( pxTCB == pxCurrentTCB )
{
configASSERT( uxSchedulerSuspended == 0 );
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
关键函数说明
prvInitialiseNewTask():初始化TCB结构,包括栈顶指针、任务入口、优先级链表等。prvAddNewTaskToReadyList():将任务加入就绪列表,若优先级高于当前任务则触发调度。prvDeleteTCB():释放TCB和栈内存(动态创建时),静态创建需用户手动释放。
注意事项
- 删除任务时需确保其未持有信号量、队列等资源,否则可能导致内存泄漏。
- 静态创建任务需保证预分配内存生命周期覆盖任务运行周期。
3953

被折叠的 条评论
为什么被折叠?



