基于源码详谈FreeRTOS内部机制之任务

 推荐使用vscode+source insight阅读代码,vscode阅读代码未使用的宏定义会变暗,source insight可以非常方便的查看函数间的调用关系。接下来开始我们的学习之旅.。。。。。。

什么是任务?

        我们常认为,C语言程序的核心是函数和变量。我们常说创建一个变量、创建一个函数,就是创建一个任务了吗?并不是。变量只是一个名字,我们无法单纯依靠变量去做任何事;函数是看到名字就能够知道是有什么作用、有什么功能的东西,它保存在flash上,在flash上的函数无需再次保存。函数和变量都是静态的,而任务应该是运行起来的函数,因为任务不仅仅包含函数和变量,还包含着它们运行所需要的环境。当任务在运行的时候,现在暂停了,但是未退出,我们为了让他下次重新运行的时候需要做些什么?
        答案当然是保存数据啦,那我们怎么保存它、保存什么?怎么恢复它、恢复什么?这就涉及到C语言的本质了,我们不在这里展开讲,后续会单开一篇文章。

任务的创建

        在freertos中,我们使用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结构体 )

名字就是任务的名字。

栈大小在freertos中是这样分配的

pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );

那么栈大小我们怎么知道要分配多大呢?这也是C语言的本质,我们会在后续单开一篇讲。
参数不重要,一般传NULL。

优先级很重要,任务运行就是高优先级运行,优先级数据越高优先级越大 在freertos源码是这样的
#define configMAX_PRIORITIES        ( 5 )    freertos   默认定义了优先级最大是5。
TCB结构体这是传出参数,进入源码我们看到它有这些东西

  ListItem_t xStateListItem;               
    ListItem_t xEventListItem;                
上面两个链表先不管,后续会讲到
    UBaseType_t uxPriority;       创建时传入的优先级          
    StackType_t * pxStack;                  创建时传入的栈大小
    char pcTaskName[ configMAX_TASK_NAME_LEN ]; 创建时传入的名字

任务的状态与优先级

任务的状态

在freertos中,任务一共有4种状态:

就绪状态:做好了一切准备工作,只等分配到CPU时间片就能运作的状态
运行状态:正在执行任务的状态
阻塞状态:因外部事件无法执行,需要等某个事件发生了才能执行,且有超时时间,时间到了就会退出阻塞态,但过了超时时间事件还没发生还得重新回到阻塞态,这会浪费CPU资源
挂起状态:没有超时时间,当有一个任务需要运行一断时间,过一段时间后再回复执行时就可以将这个任务放入挂起状态

任务的优先级

在task.c文件中, 我们看到有 pxReadyTasksLists[ configMAX_PRIORITIES ] pxDelayedTaskList  xPendingReadyList三类链表。任务的调度就是靠这三类执行的,


我们实操一下,首先先写了俩个任务

xTaskCreate( vTask1, "Task 1", 1000, NULL, 1, NULL );
xTaskCreate( vTask2, "Task 2", 1000, NULL, 1, NULL );

因为configMAX_PRIORITIES 默认是5,所以有pxReadyTasksLists[0] ~~pxReadyTasksLists[4],总共5个链表。

在源码中,通过  prvAddTaskToReadyList( pxNewTCB );传入就绪链表 

放入的位置是链表的最后,在同优先级情况下是先来先到原则,最新创建的任务先运行,就是人类世界的排队,源码是这样呈现的
 

vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); 

如果创建的任务的优先级高于当前任务,那么它应该立即运行。

if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
        {
            taskYIELD_IF_USING_PREEMPTION();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

在优先级为0下,还有一个空闲任务,空闲任务永远优先级最低,永远先礼让其他任务。
 

if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
                {
                    taskYIELD();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

那空闲任务存在的意义是什么?如垃圾回收处理。

在其他高级语言中如JAVA有JVM,JVM有自带的垃圾回收机制,不需要程序去执行,但在C语言中却没有,所以有个空闲任务可以去执行一些清理任务

任务的调度

在freertos中谁来调度任务呢?

答案是tick中断。在freertos中是1m执行一次。tick可以挑出优先级高的任务先执行,也会判断是否要去切换任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值