freertos笔记-任务基本构造

红叶何时落水

每个任务都有他特有的属性,这些属性记录着当前任务的状态
相当于新建一个任务对象 对象类为TCB_t/tskTCB动态创建
 

typedef struct tskTaskControlBlock
{
    volatile StackType_t    *pxTopOfStack;//指向该任务堆栈的最后一项 pxTopOfStack为堆栈栈顶指针 32位    
    ListItem_t            xStateListItem;//定义一个链表 项 ,这个项有着必要的信息  状态链表项 用来记录该任务的状态,是挂起还是就绪
    ListItem_t            xEventListItem;//事件列表项    用于记录自己是否处于延时列表中    
    UBaseType_t            uxPriority;    //任务优先级 运行过程中要被识别的优先级 可以被优先级继承机制改变        
    StackType_t            *pxStack;//任务堆栈起始地址 分配的堆栈的起始地址            
    char                pcTaskName[ configMAX_TASK_NAME_LEN ];//任务名字 没啥用
    #if ( configUSE_MUTEXES == 1 )
        UBaseType_t        uxBasePriority;//任务基础优先级,优先级反转的时候用到,就是说他初始化的那个优先级                
        UBaseType_t        uxMutexesHeld;//任务获取到的互斥信号量个数
    #endif
    #if( configUSE_TASK_NOTIFICATIONS == 1 )        
        volatile uint32_t ulNotifiedValue;//任务通知值        
        volatile uint8_t ucNotifyState;//任务状态    用于任务通知操作
    #endif
} tskTCB;
这个是上面含有的链表 项  的定义
struct xLIST_ITEM
{
    configLIST_VOLATILE TickType_t xItemValue;            /*< 列表项的值,降序排列 */
    struct xLIST_ITEM * configLIST_VOLATILE pxNext;        /*< 链表连接 */
    struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;    /*< 双向链表 */
    void * pvOwner;                                        /*<指向那个任务对象TCB_t 中的变量xStateListItem的pvOwner指向TCB,当任务处于就绪态时,pvContainer指向就绪列表其余状态,同理 */ 
    void * configLIST_VOLATILE pvContainer;                /*<指向列表项所属的列表 */
};typedef struct xLIST_ITEM ListItem_t;    


创建一个新任务

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, //任务函数 这里是一个指针常量,表示函数地址
                        const char * const pcName, //任务名 没啥用
                        const uint16_t usStackDepth, //堆栈大小 单位是字而非字节 不包括TCB
                        void * const pvParameters, //任务函数的参数,指针类型,建议结构体传参
                        UBaseType_t uxPriority, //优先级
                        TaskHandle_t * const pxCreatedTask )//句柄 其实就是任务堆栈


删除任务
vTaskDelete();//删除任务,并在空闲任务中释放空间(堆栈以及TCB的空间)TCB空间如果是动态创建任务的话,就是自动分配自动回收,如果是静态创建,就需要初始化一下,而且必须是初始化StaticTask_t该结构体,而不是值初始化一个结构体指针

将该任务挂起,只有调用任务恢复函数 vTaskResume()或 xTaskResumeFromISR()才会恢复该任务,其他的队列,任务通知,delay都不能将其唤醒
xTaskToSuspend(句柄);句柄为NULL时挂起自己 可以通过函数 xTaskGetHandle()来根据任务名字
xTaskResumeFromISR();//中断中调用这类函数,必须检查一下中断结束后的任务与进入中断时的任务是不是同一个,如果不是,就要进行上下文切换,就是改变PSP的指向

YieldRequired=xTaskResumeFromISR(Task2Task_Handler);//恢复任务 2
if(YieldRequired==pdTRUE)
{
    /*如果函数 xTaskResumeFromISR()返回值为 pdTRUE,那么说明要恢复的这个
    任务的任务优先级等于或者高于正在运行的任务(被中断打断的任务),所以在
    退出中断的时候一定要进行上下文切换!*/
    portYIELD_FROM_ISR(YieldRequired);
}

删除任务
vTaskDelete();
1. 先获取要删除任务的句柄 参数为NULL,就获取调用该任务的句柄 prvGetTCBFromHandle()
    #define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB : ( TCB_t * ) ( pxHandle ) )
2. 从就绪列表中删除该任务
3. 列表优先级切换

    #define taskRESET_READY_PRIORITY( uxPriority )                                                        \
    {                                                                                                    \
        if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 )    \//判断这个优先级列表里的任务还有没有,如果这个优先级的列表里没有了任务,就执行下面的语句
        {                                                                                                \
            portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) );                            \//重置优先级
        }                                                                                                \
    }


4. 检查是否处于延迟列表中,是的话,从延时列表中删掉
5. 如果要删除的任务正在运行,就将其添加到xTasksWaitingTermination列表中,然后由空闲任务释放其空间
   ++uxDeletedTasksWaitingCleanUp;表示有多少个任务要被清理
6. 如果要删除的任务没有在运行 prvDeleteTCB() 释放空间 并--uxCurrentNumberOfTasks;表示当前可运行任务数减一

   prvResetNextTaskUnblockTime();重新计算下一个任务解锁的时间
    static void prvResetNextTaskUnblockTime( void )
    {
        TCB_t *pxTCB;

        if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
        {
            xNextTaskUnblockTime = portMAX_DELAY;
        }
        else
        {
            ( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );//获取列表中的第一个任务
            xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) );//延时时间等于任务结构体里的value值,升序排列,value值越大,排的越后面,延时越长
        }
    }


7. 如果要删除的任务正在运行,切换上下文


任务挂起
vTaskSuspend() 不能重复挂起,就是说,只要调用恢复API就会被解除悬挂
1. 获取要挂起任务的句柄
2. 就绪,延时列表中移除该任务,并判断当前优先级 它会使xdelay失效,那就意味着接触悬挂,立马加入就绪状态
3. 插入挂起列表 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
4. prvResetNextTaskUnblockTime();
5. 如果该任务正在运行,切换上下文 portYIELD_WITHIN_API();
6. 如果调度器不工作,那么手动切换当前任务指针 vTaskSwitchContext();

恢复被挂起的任务
 

vTaskResume()
{
    TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume; 
    if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) ) 
    {
        taskENTER_CRITICAL(); 
        {
            if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) 
            {
                ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); 
                prvAddTaskToReadyList( pxTCB );
                if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) 
                {
                taskYIELD_IF_USING_PREEMPTION();
                }
            }
        }
        taskEXIT_CRITICAL(); 
    }
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

红叶落水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值