FreeRTOS静态和动态创建任务

简介: FreeRTOS静态和动态创建任务

静态创建任务


源代码 xTaskCreateStatic

静态的方式创建任务,需要用户先申请任务控制模块和任务栈需要的内存(一般使用静态内存),然后把内存地址传递给函数,函数负责其他初始化。

函数按顺序完成:

* 根据用户传递内存,初始化任务 TCB

* 初始化任务堆栈

* 将新建任务加入到就绪链表中

* 如果调度器运行,新任务优先级更高,触发系统切换

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 )
{
    TCB_t *pxNewTCB;
    TaskHandle_t xReturn;
    configASSERT( puxStackBuffer != NULL );
    configASSERT( pxTaskBuffer != NULL );
    if ((pxTaskBuffer != NULL) && (puxStackBuffer != NULL)) 
    {
        // 设置用户传递进来的任务控制块和栈的内存地址到对应指针变量
        pxNewTCB = (TCB_t *)pxTaskBuffer; 
        pxNewTCB->pxStack = (StackType_t *)puxStackBuffer;
        #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
        {
            // 标识这个任务控制块和栈内存时静态的
            // 删除任务的时候, 系统不会做内存回收处理
            pxNewTCB->ucStaticallyAllocated = 
                tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
        }
        #endif
        // 初始化任务控制块 下文介绍
        prvInitialiseNewTask( pxTaskCode, pcName,
            ulStackDepth, pvParameters, uxPriority, 
            &xReturn, pxNewTCB, NULL );
        // 把新任务插入就绪链表 下文介绍
        prvAddNewTaskToReadyList( pxNewTCB );
    }
    else 
    {
        xReturn = NULL;
    }
    return xReturn;
}



动态创建任务


源代码 xTaskCreate

动态创建任务, 调用函数内部向系统申请创建新任务所需的内存,包括任务控制块和栈。 所以调用这个函数,在内存堆空间不足或者碎片话的情况下,可能创建新任务失败,需要判断函数执行后是否成功返回。 其源码解析如下所示。

BaseType_t xTaskCreate( 
    TaskFunction_t pxTaskCode,
    const char * const pcName,
    const uint16_t usStackDepth,
    void * const pvParameters,
    UBaseType_t uxPriority,
    TaskHandle_t * const pxCreatedTask )    
{
    TCB_t *pxNewTCB;
    BaseType_t xReturn;
    // 如果是向下增长的栈, 先申请栈内存再申请任务控制块内存
    // 可以避免栈溢出覆盖了自己任务控制块
    // 对应向上增长的则相反
    // 在旧版本 V8.0.0 中没有这么处理,统一先 TCB 后 Stack
    // 项目上碰到平台栈向下增长, 栈溢出错时候覆盖了自己的 TCB 
    // 导致调试的时候无法获取出错任务信息(比如任务名)
    #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 = (StackType_t *)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 /* configSUPPORT_STATIC_ALLOCATION */
        // 初始任务控制块
        prvInitialiseNewTask(pxTaskCode, pcName,
            (uint32_t)usStackDepth, pvParameters, 
            uxPriority, pxCreatedTask, pxNewTCB, NULL );
        // 将新任务插入到就绪链表  
        prvAddNewTaskToReadyList( pxNewTCB );
        xReturn = pdPASS;
    }
    else
    {
        // 创建任务失败,返回错误码
        xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
    }
    return xReturn;
}


目录
相关文章
|
17天前
|
Java
【专栏】Java反射机制,该机制允许程序在运行时获取类信息、动态创建对象、调用方法和访问属性
【4月更文挑战第27天】本文探讨了Java反射机制,该机制允许程序在运行时获取类信息、动态创建对象、调用方法和访问属性。反射通过Class、Constructor、Method和Field类实现。文中列举了反射的应用场景,如动态创建对象、调用方法、访问属性和处理注解,并提供了相关实例代码演示。
|
7月前
|
编译器 调度
FreeRTOS任务的创建(动态方法和静态方法)
FreeRTOS任务的创建(动态方法和静态方法)
260 0
|
9月前
|
设计模式 Java BI
彻底搞懂访问者模式的静态、动态和伪动态分派
每到年底,管理层就要开始评定员工一年的工作绩效,员工分为工程师和经理;管理层有CEO和CTO。那么CTO关注工程师的代码量、经理的新产品数量;CEO关注工程师的KPI、经理的KPI及新产品数量。
90 0
|
11月前
|
程序员 编译器 数据安全/隐私保护
内存、引用、封装、函数
内存、引用、封装、函数
53 0
|
Java 编译器
静态连接、动态连接、静态分派、动态分派、单分派、多分派、虚方法、非虚方法
对于从事java开发的人一定见过这些概念,但是不去仔细研究却又不清楚这些都是什么,有时候又感觉几个感念在说一个事情,云里雾里,我也是在这种情况下对这几种概念进行学习的,这里对他们的联系进行总结。
96 0
|
存储 缓存 算法
JVM系列之:JVM是如何处理我们定义的对象生成代码
JVM系列之:JVM是如何处理我们定义的对象生成代码
80 0
JVM系列之:JVM是如何处理我们定义的对象生成代码
|
Java
静态链接,静态分派,动态链接
静态链接,静态分派,动态链接
123 0
|
Linux
Linux系统编程-(pthread)线程的使用案例(分离属性、清理函数等)
这篇文章介绍Linux下线程的创建与基本使用案例,主要是案例代码为主;相关的函数详细介绍在上篇文章里已经介绍过了。
190 0