zoukankan      html  css  js  c++  java
  • 1.FreeRTOS List简易分析

    FreeRTOS从简单的List入手

    • 架构:Cortex-M3
    • 版本:FreeRTOS V9.0.0
    • 前言:打开List.c文件来看,200多行,并不是很多,详细看内容,其实就是一个双向链表的增和删

    1.结构体List_t

    typedef struct xLIST  
    {  
       listFIRST_LIST_INTEGRITY_CHECK_VALUE		/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */  
       configLIST_VOLATILE UBaseType_t uxNumberOfItems;  
       ListItem_t * configLIST_VOLATILE pxIndex;	/*< Used to walk through the list.  Points to the last item returned by a call to   listGET_OWNER_OF_NEXT_ENTRY (). */  
       MiniListItem_t xListEnd;			/*< List item that contains the maximum possible item value meaning it is   always at the end of the list and is therefore used as a marker. */  
       listSECOND_LIST_INTEGRITY_CHECK_VALUE		/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */  
    } List_t; 
    
    • 能力有限只能挑几个来讲C
    变量名 作用
    listFIRST_LIST_INTEGRITY_CHECK_VALUE 检查数据是否完整
    uxNumberOfItems 挂接在这个链表的链表项数目
    xListEnd 指向链表的尾部
    我个人理解这个**MiniListItem_t xListEnd**,其实它就是mini的ListItem,仅仅是因为要节省内存,把它作为尾结点。 MiniListItem.xItemValue在32位的平台下,它的值默认为0xffffffff

    2.结构体xLIST_ITEM

    struct xLIST_ITEM
    {
    	listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE			/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
    	configLIST_VOLATILE TickType_t xItemValue;			/*< The value being listed.  In most cases this is used to sort the list in descending order. */
    	struct xLIST_ITEM * configLIST_VOLATILE pxNext;		/*< Pointer to the next ListItem_t in the list. */
    	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;	/*< Pointer to the previous ListItem_t in the list. */
    	void * pvOwner;										/*< Pointer to the object (normally a TCB) that contains the list item.  There is therefore a two way link between the object containing the list item and the list item itself. */
    	void * configLIST_VOLATILE pvContainer;				/*< Pointer to the list in which this list item is placed (if any). */
    	listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE			/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
    };
    
    变量名 作用
    xItemValue 列表项值,用于按降序对列表进行排序
    pxNext 指向下一个列表项
    pxPrevious 指向前一个列表项
    pvOwner 指向任务块TCB
    pvContainer 指向属于的链表

    正如我开头所说,结构体ListItem就是链表结点,结构体List就是链表,ListItem链到List上。

    3.链表的操作函数

    3.1链表的初始化

    void vListInitialise( List_t * const pxList )
    {
    	/* The list structure contains a list item which is used to mark the
    	end of the list.  To initialise the list the list end is inserted
    	as the only list entry. */
    	pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );			/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
    
    	/* The list end value is the highest possible value in the list to
    	ensure it remains at the end of the list. */
    	pxList->xListEnd.xItemValue = portMAX_DELAY;
    
    	/* The list end next and previous pointers point to itself so we know
    	when the list is empty. */
    	pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );	/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
    	pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
    
    	pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
    
    	/* Write known values into the list if
    	configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
    	listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
    	listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
    }
    
    ->链表的初始化流程
    1. pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ) 指向尾结点
    2. pxList->xListEnd.xItemValue = portMAX_DELAY在32位架构下 portMAX_DELAY为0xFFFFFFFF
    3. pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ) next指向尾结点
    4. pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ) previous指向尾结点
    5. pxList->uxNumberOfItems = ( UBaseType_t ) 0U 设置当前挂载结点为0

    3.2链表项的初始化

    void vListInitialiseItem( ListItem_t * const pxItem )
    {
    	/* Make sure the list item is not recorded as being on a list. */
    	pxItem->pvContainer = NULL;
    
    	/* Write known values into the list item if
    	configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
    	listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
    	listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
    }
    
    ->链表项的初始化流程

    只需要pxItem->pvContainer = NULL,把这个链表项指向的链表置空即可 ,表示链表项不属于任何链表


    3.3向链表增加链表项:

    3.3.1. 尾插
    void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
    {
    ListItem_t * const pxIndex = pxList->pxIndex;
    
    	/* Only effective when configASSERT() is also defined, these tests may catch
    	the list data structures being overwritten in memory.  They will not catch
    	data errors caused by incorrect configuration or use of FreeRTOS. */
    	listTEST_LIST_INTEGRITY( pxList );
    	listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
    
    	/* Insert a new list item into pxList, but rather than sort the list,
    	makes the new list item the last item to be removed by a call to
    	listGET_OWNER_OF_NEXT_ENTRY(). */
    	pxNewListItem->pxNext = pxIndex;
    	pxNewListItem->pxPrevious = pxIndex->pxPrevious;
    
    	/* Only used during decision coverage testing. */
    	mtCOVERAGE_TEST_DELAY();
    
    	pxIndex->pxPrevious->pxNext = pxNewListItem;
    	pxIndex->pxPrevious = pxNewListItem;
    
    	/* Remember which list the item is in. */
    	pxNewListItem->pvContainer = ( void * ) pxList;
    
    	( pxList->uxNumberOfItems )++;
    }
    
    ->尾插流程
    1. ListItem_t * const pxIndex = pxList->pxIndex 获取最后一个结点
    2. pxNewListItem->pxNext = pxIndex 将新结点的next指向最后一个结点
    3. pxNewListItem->pxPrevious = pxIndex->pxPrevious 将新结点的previous指向最后结点的前一项
    4. pxIndex->pxPrevious->pxNext = pxNewListItem 将最后结点的next指向新结点
    5. pxIndex->pxPrevious = pxNewListItem 将最后结点的previous指向新结点
    6. pxNewListItem->pvContainer = ( void * ) pxList 新结点属于pxList下的结点
    7. ( pxList->uxNumberOfItems )++ pxList结点的总数目加1

    3.3.2.升序插入
    void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
    {
    ListItem_t *pxIterator;
    const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
    
    	/* Only effective when configASSERT() is also defined, these tests may catch
    	the list data structures being overwritten in memory.  They will not catch
    	data errors caused by incorrect configuration or use of FreeRTOS. */
    	listTEST_LIST_INTEGRITY( pxList );
    	listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
    
    	/* Insert the new list item into the list, sorted in xItemValue order.
    
    	If the list already contains a list item with the same item value then the
    	new list item should be placed after it.  This ensures that TCB's which are
    	stored in ready lists (all of which have the same xItemValue value) get a
    	share of the CPU.  However, if the xItemValue is the same as the back marker
    	the iteration loop below will not end.  Therefore the value is checked
    	first, and the algorithm slightly modified if necessary. */
    	if( xValueOfInsertion == portMAX_DELAY )
    	{
    		pxIterator = pxList->xListEnd.pxPrevious;
    	}
    	else
    	{
    		/* *** NOTE ***********************************************************
    		If you find your application is crashing here then likely causes are
    		listed below.  In addition see http://www.freertos.org/FAQHelp.html for
    		more tips, and ensure configASSERT() is defined!
    		http://www.freertos.org/a00110.html#configASSERT
    
    			1) Stack overflow -
    			   see http://www.freertos.org/Stacks-and-stack-overflow-checking.html
    			2) Incorrect interrupt priority assignment, especially on Cortex-M
    			   parts where numerically high priority values denote low actual
    			   interrupt priorities, which can seem counter intuitive.  See
    			   http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
    			   of configMAX_SYSCALL_INTERRUPT_PRIORITY on
    			   http://www.freertos.org/a00110.html
    			3) Calling an API function from within a critical section or when
    			   the scheduler is suspended, or calling an API function that does
    			   not end in "FromISR" from an interrupt.
    			4) Using a queue or semaphore before it has been initialised or
    			   before the scheduler has been started (are interrupts firing
    			   before vTaskStartScheduler() has been called?).
    		**********************************************************************/
    
    		for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
    		{
    			/* There is nothing to do here, just iterating to the wanted
    			insertion position. */
    		}
    	}
    
    	pxNewListItem->pxNext = pxIterator->pxNext;
    	pxNewListItem->pxNext->pxPrevious = pxNewListItem;
    	pxNewListItem->pxPrevious = pxIterator;
    	pxIterator->pxNext = pxNewListItem;
    
    	/* Remember which list the item is in.  This allows fast removal of the
    	item later. */
    	pxNewListItem->pvContainer = ( void * ) pxList;
    
    	( pxList->uxNumberOfItems )++;
    }
    
    ->升序插入流程
    1. const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; 获取插入的结点值

    2. for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) 遍历到小于 xValueOfInsertion 的值

    pxNewListItem->pxNext = pxIterator->pxNext;
    pxNewListItem->pxNext->pxPrevious = pxNewListItem;
    pxNewListItem->pxPrevious = pxIterator;
    pxIterator->pxNext = pxNewListItem;
    

    做的就是把新结点插入到遍历后pxIterator的Next

    1. pxNewListItem->pvContainer = ( void * ) pxList 该结点属于List

    2. List的结点数目加1


    3.4 删除链表项

    UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
    {
    /* The list item knows which list it is in.  Obtain the list from the list
    item. */
    List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;
    
    	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
    	pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
    
    	/* Only used during decision coverage testing. */
    	mtCOVERAGE_TEST_DELAY();
    
    	/* Make sure the index is left pointing to a valid item. */
    	if( pxList->pxIndex == pxItemToRemove )
    	{
    		pxList->pxIndex = pxItemToRemove->pxPrevious;
    	}
    	else
    	{
    		mtCOVERAGE_TEST_MARKER();
    	}
    
    	pxItemToRemove->pvContainer = NULL;
    	( pxList->uxNumberOfItems )--;
    
    	return pxList->uxNumberOfItems;
    }
    
    
    ->删除流程
    1. List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer; 找到该链表项的所在链表

    2. pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
      pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
      

      A_Item -> B_Item -> C_Item,假设B为要删除的Item,结果为A_Item - > CItem

    3. if( pxList->pxIndex == pxItemToRemove )
      {
      	pxList->pxIndex = pxItemToRemove->pxPrevious;
      }
      

      如果该Item为最后,A_Item -> Last_Item, 那么A就会成为Lash_Item

    4. pxItemToRemove->pvContainer = NULL;
      ( pxList->uxNumberOfItems )--;
      

      该Item不属于任何List,并把原List的Item数目减1

  • 相关阅读:
    剑指offer(14)链表中倒数第K个节点
    剑指offer(13)调整数组顺序使奇数位于偶数前面
    跨域资源共享CORS
    同源政策
    剑指offer(12)数值的整数次方
    剑指offer(11)二进制中1的个数
    面试金典——交点
    LeetCode——简化路径
    LeetCode——跳跃游戏 I-II
    LeetCode——最大矩形
  • 原文地址:https://www.cnblogs.com/r1chie/p/14117403.html
Copyright © 2011-2022 走看看