freertos任务调度关键函数理解 vTaskSwitchContext


void vTaskSwitchContext(void)
{

    //my_printf( "uxSchedulerSuspended = %d\n", uxSchedulerSuspended );
    /* 调度器处于挂起状态 */
    if (uxSchedulerSuspended != (UBaseType_t)pdFALSE) {
        /**
         * The scheduler is currently suspended - do not allow a context
         * switch.
         */
        xYieldPending = pdTRUE;
    } else {
        xYieldPending = pdFALSE;
        traceTASK_SWITCHED_OUT();


        /* Check for stack overflow, if configured. */
        taskCHECK_FOR_STACK_OVERFLOW();

        /* Before the currently running task is switched out, save its errno. */
        #if (configUSE_POSIX_ERRNO == 1)
        {bbb
            pxCurrentTCB->iTaskErrno = FreeRTOS_errno;
        }
        #endif

        /**
         * Select a new task to run using either the generic C or port
         * optimised asm code.  debug_stamp
         * 选择优先级最高的任务
         */
        //taskSELECT_HIGHEST_PRIORITY_TASK();
        UBaseType_t uxTopPriority;                                                                                                                                                        
        /* Find the highest priority list that contains ready tasks. */                        
        //portGET_HIGHEST_PRIORITY(uxTopPriority, uxTopReadyPriority);    
        //#define portGET_HIGHEST_PRIORITY xxx( uxTopPriority, uxReadyPriorities ) 


        //my_printf( "ccccuxTopReadyPriority = %#x\n", uxTopReadyPriority );
        uxTopPriority = ( 31UL - ( uint32_t ) ucPortCountLeadingZeros( ( uxTopReadyPriority ) ) );
        //configASSERT(listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[uxTopPriority])) > 0);    


        
        //listGET_OWNER_OF_NEXT_ENTRY(pxCurrentTCB, &(pxReadyTasksLists[uxTopPriority])); 


        //|------->volatile UBaseType_t uxNumberOfItems = 1    //链表中元素的个数
        //| |<-----ListItem_t *pxIndex;                           //总是指向xListEnd节点,在链表尾部插入的时候,方便找到位置    
        //| |->|-->TickType_t xItemValue = portMAX_DELAY       [MiniListItem_t xListEnd]   
        //|    |   struct xLIST_ITEM *pxNext;     ----->|      //后继节点
        //|    |   struct xLIST_ITEM *pxPrevious; ----->|      //前驱节点    
        //|    |                                        |
        //|    |   TickType_t xItemValue; <-------------|      //链表节点的值
        //|    |<--struct xLIST_ITEM *pxNext;                  //后继节点
        //|    |<--struct xLIST_ITEM *pxPrevious;              //前驱节点
        //|        void * pvOwner;                             //保存私有数据
        //|<------ struct xLIST *pxContainer;                  //节点所在的链表


        //|------->volatile UBaseType_t uxNumberOfItems = 1    //链表中元素的个数
        //| |<-----ListItem_t *pxIndex;                           //总是指向xListEnd节点,在链表尾部插入的时候,方便找到位置    
        //| |  |-->TickType_t xItemValue = portMAX_DELAY       [MiniListItem_t xListEnd]   
        //| |  |   struct xLIST_ITEM *pxNext;     ----->|      //后继节点
        //| |  |   struct xLIST_ITEM *pxPrevious; ----->|      //前驱节点    
        //| |  |                                        |
        //| |--|-->TickType_t xItemValue; <-------------|      //链表节点的值
        //|    |<--struct xLIST_ITEM *pxNext;                  //后继节点
        //|    |<--struct xLIST_ITEM *pxPrevious;              //前驱节点
        //|        void * pvOwner;                             //保存私有数据
        //|<------ struct xLIST *pxContainer;                  //节点所在的链表


        

        
        my_printf( "\nuxTopPriority = %d\n", uxTopPriority );
        my_printf( "pxCurrentTCB->pcTaskName1 = %s\n", pxCurrentTCB->pcTaskName );
        List_t * const pxConstList = &pxReadyTasksLists[uxTopPriority];    
        //my_printf( "pxConstList = %p\n", pxConstList );
        my_printf( "pxConstList->pxIndex before = %p\n", pxConstList->pxIndex );

        
        /* Increment the index to the next item and return the item, ensuring */           
        /* we don't return the marker used at the end of the list.    */                       
        pxConstList->pxIndex = pxConstList->pxIndex->pxNext;
        //此处有指针的指向偏移 由 xListEnd -> xLIST_ITEM

        my_printf( "pxConstList->pxIndex hou = %p\n", pxConstList->pxIndex );
        my_printf( " &pxConstList->xListEnd = %p\n",  &pxConstList->xListEnd );
        
        if( (void *)pxConstList->pxIndex == (void *)&pxConstList->xListEnd ){                                                                                   
            pxConstList->pxIndex = pxConstList->pxIndex->pxNext;    
            my_printf( "pxConstList->pxIndexxx = %p\n", pxConstList->pxIndex );

            //空闲任务由于不能挂起,其指向内容有些不一样 pxIndex->pxNext 指向 &xListEnd, 而不是指向xLIST_ITEM
            //而对于其他有挂起和恢复的任务 不一样
            //空闲任务不会有链表xLIST_ITEM的删除和插入动作
            //第一次进空闲任务不会走这里 后续由于没有删除和插入对pxIndex复位 
            //pxConstList->pxIndex = pxConstList->pxIndex->pxNext; 指向了xLIST_ITEM 
            //然后达到了循环的稳定点 
            //总结下来:第一次指向 &xListEnd,后续运行指向 xLIST_ITEM 
            //为啥后续不交错指向? 2次运行 pxConstList->pxIndex = pxConstList->pxIndex->pxNext; 回到原点.
            //第一次运行:
            //|------->volatile UBaseType_t uxNumberOfItems = 1    //链表中元素的个数
            //| |<-----ListItem_t *pxIndex;                           //总是指向xListEnd节点,在链表尾部插入的时候,方便找到位置    
            //| |->|-->TickType_t xItemValue = portMAX_DELAY       [MiniListItem_t xListEnd]   
            //|    |   struct xLIST_ITEM *pxNext;     ----->|      //后继节点
            //|    |   struct xLIST_ITEM *pxPrevious; ----->|      //前驱节点    
            //|    |                                        |
            //|    |   TickType_t xItemValue; <-------------|      //链表节点的值 xLIST_ITEM xLIST_ITEM
            //|    |<--struct xLIST_ITEM *pxNext;                  //后继节点
            //|    |<--struct xLIST_ITEM *pxPrevious;              //前驱节点
            //|        void * pvOwner;                             //保存私有数据
            //|<------ struct xLIST *pxContainer;                  //节点所在的链表

            //第2次运行:
            //|------->volatile UBaseType_t uxNumberOfItems = 1    //链表中元素的个数
            //| |<-----ListItem_t *pxIndex;                           //总是指向xListEnd节点,在链表尾部插入的时候,方便找到位置    
            //| |  |-->TickType_t xItemValue = portMAX_DELAY       [MiniListItem_t xListEnd]   
            //| |  |   struct xLIST_ITEM *pxNext;     ----->|      //后继节点
            //| |  |   struct xLIST_ITEM *pxPrevious; ----->|      //前驱节点    
            //| |  |                                        |
            //| |--|-->TickType_t xItemValue; <-------------|      //链表节点的值 xLIST_ITEM xLIST_ITEM
            //|    |<--struct xLIST_ITEM *pxNext;                  //后继节点
            //|    |<--struct xLIST_ITEM *pxPrevious;              //前驱节点
            //|        void * pvOwner;                             //保存私有数据
            //|<------ struct xLIST *pxContainer;                  //节点所在的链表

            

            
        }                                                                                   
        pxCurrentTCB = pxConstList->pxIndex->pvOwner;        
        my_printf( "pxCurrentTCB->pcTaskName2 = %s\n", pxCurrentTCB->pcTaskName );

    
        traceTASK_SWITCHED_IN();

        /* After the new task is switched in, update the global errno. */
        #if (configUSE_POSIX_ERRNO == 1)
        {
            FreeRTOS_errno = pxCurrentTCB->iTaskErrno;
        }
        #endif
    }
}
 

内容概要:文章详细介绍了ETL工程师这一职业,解释了ETL(Extract-Transform-Load)的概念及其在数据处理中的重要性。ETL工程师负责将分散、不统一的数据整合为有价值的信息,支持企业的决策分析。日常工作包括数据整合、存储管理、挖掘设计支持和多维分析展现。文中强调了ETL工程师所需的核心技能,如数据库知识、ETL工具使用、编程能力、业务理解能力和问题解决能力。此外,还盘点了常见的ETL工具,包括开源工具如Kettle、XXL-JOB、Oozie、Azkaban和海豚调度,以及企业级工具如TASKCTL和Moia Comtrol。最后,文章探讨了ETL工程师的职业发展路径,从初级到高级的技术晋升,以及向大数据工程师或数据产品经理的横向发展,并提供了学习资源和求职技巧。 适合人群:对数据处理感兴趣,尤其是希望从事数据工程领域的人士,如数据分析师、数据科学家、软件工程师等。 使用场景及目标:①了解ETL工程师的职责和技能要求;②选择适合自己的ETL工具;③规划ETL工程师的职业发展路径;④获取相关的学习资源和求职建议。 其他说明:随着大数据技术的发展和企业数字化转型的加速,ETL工程师的需求不断增加,尤其是在金融、零售、制造、人工智能、物联网和区块链等领域。数据隐私保护法规的完善也使得ETL工程师在数据安全和合规处理方面的作用更加重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值