任务创建是FreeRTOS系统启动的第一个步骤,前面在启动调度器的时候先创建了空闲任务,然后再由调度器跳到任务里面去执行。任务创建函数里面做了很多的工作,先会为任务堆栈和任务控制块分配内存并初始化它们,然后将任务添加到就绪列表里面,等待调度器来调用。
任务创建的接口定义如下:
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 )
形参代表的意义如下:
pxTaskCode 任务函数入口地址
pcName 任务名称
usStackDepth 任务堆栈大小
pvParameters 传递给任务函数的参数
uxPriority 任务优先级
pxCreatedTask 任务控制块句柄
源码分析:
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 )
{
/* 如果堆栈向上增长,则先分配任务控制块 */
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL )
{
/* 分配任务堆栈,具体内存分配实现在内存管理章节分析 */
pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
if( pxNewTCB->pxStack == NULL )
{
/* 堆栈分配失败就释放之前分配的任务控制块内存 */
vPortFree( pxNewTCB );
pxNewTCB = NULL;
}
}
}
#else
{
StackType_t *pxStack;
/* 如果堆栈向下增长,则先分配任务堆栈 */
pxStack = pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
if( pxStack != NULL )
{
/* 堆栈分配成功后分配任务控制块空间 */
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL )
{
/* 初始化任务控制块的堆栈指针 */
pxNewTCB->pxStack = pxStack;
}
else
{
/* 任务控制块分配失败就释放之间分配的任务堆栈内存 */
vPortFree( pxStack );
}
}
else
{
pxNewTCB = NULL;
}
}
#endif
if( pxNewTCB != NULL )
{
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
{
/* 可以静态也可以动态分配的情况下默认使用动态分配内存 */
pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
}
#endif
/* 初始化任务 */
prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
/* 把列表项添加到就绪列表中,优先级高过原来的话就请求一次