FreeRTOS 筆記之⑧:任務延時列表的實現

目錄

1. 任務延時列表的工作原理

2. 實現任務延時列表

2.1 定義任務延時列表

2.2 任務延時列表初始化

2.3 定義xNextTaskUnblockTime


在本章之前,爲了實現任務的阻塞延時,在任務控制塊中內置了一個延時變量xTicksToDelay。每當任務需要延時的時候,就初始化xTicksToDelay需要延時的時間,然後將任務掛起,這裏的掛起只是將任務在優先級位圖表uxTopReadyPriority中對應的位清零,並不會將任務從就緒列表中刪除。當每次時基中斷(SysTick中斷)來臨時,就掃描就緒列表中的每個任務的xTicksToDelay,如果xTicksToDelay大於0則遞減一次,然後判斷xTicksToDelay是否爲0,如果爲0則表示延時時間到,將該任務就緒(即將任務在優先級位圖表uxTopReadyPriority中對應的位置位),然後進行任務切換。這種延時的缺點是,在每個時基中斷中需要對所有任務都掃描一遍,費時,優點是容易理解。這種方法其實也是大多數人的常規操作。之所以先這樣講解是爲了慢慢地過度到FreeRTOS任務延時列表的講解。

1. 任務延時列表的工作原理

在FreeRTOS中,有一個任務延時列表(實際上有兩個,爲了方便講解原理,我們假裝合併爲一個,其實兩個的作用是一樣的),當任務需要延時的時候,則先將任務掛起,即先將任務從就緒列表刪除,然後插入到任務延時列表,同時更新下一個任務的解鎖時刻變量:xNextTaskUnblockTime的值。

xNextTaskUnblockTime的值等於系統時基計數器的值xTickCount加上任務需要延時的值xTicksToDelay。當系統時基計數器xTickCount的值與xNextTaskUnblockTime相等時,就表示有任務延時到期了,需要將該任務就緒。與RT-Thread和μC/OS在解鎖延時任務時要掃描定時器列表這種時間不確定性的方法相比,FreeRTOS這個xNextTaskUnblockTime全局變量設計的非常巧妙。

任務延時列表表維護着一條雙向鏈表,每個節點代表了正在延時的任務,節點按照延時時間大小做升序排列。當每次時基中斷(SysTick中斷)來臨時,就拿系統時基計數器的值xTickCount與下一個任務的解鎖時刻變量xNextTaskUnblockTime的值相比較,如果相等,則表示有任務延時到期,需要將該任務就緒,否則只是單純地更新系統時基計數器xTickCount的值,然後進行任務切換。

2. 實現任務延時列表

2.1 定義任務延時列表

任務延時列表在task.c中定義

static List_t xDelayedTaskList1;
static List_t xDelayedTaskList2;
static List_t * volatile pxDelayedTaskList;
static List_t * volatile pxOverflowDelayedTaskList;
  • FreeRTOS定義了兩個任務延時列表,當系統時基計數器xTickCount沒有溢出時,用一條列表,當xTickCount溢出後,用另外一條列表

  • 任務延時列表指針,指向xTickCount沒有溢出時使用的那條列表

  • 任務延時列表指針,指向xTickCount溢出時使用的那條列表。

2.2 任務延時列表初始化

任務延時列表屬於任務列表的一種,在prvInitialiseTaskLists()函數中初始化

/* 初始化任務相關的列表 */
void prvInitialiseTaskLists( void )
{
    UBaseType_t uxPriority;
    
    /* 初始化就緒列表 */
    for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
	{
		vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
	}
    
    vListInitialise( &xDelayedTaskList1 );
	vListInitialise( &xDelayedTaskList2 );
    
    pxDelayedTaskList = &xDelayedTaskList1;
	pxOverflowDelayedTaskList = &xDelayedTaskList2;
}

2.3 定義xNextTaskUnblockTime

xNextTaskUnblockTime是一個在task.c中定義的靜態變量,用於表示下一個任務的解鎖時刻。xNextTaskUnblockTime的值等於系統時基計數器的值xTickCount加上任務需要延時值xTicksToDelay。當系統時基計數器xTickCount的值與xNextTaskUnblockTime相等時,就表示有任務延時到期了,需要將該任務就緒。

xNextTaskUnblockTime在vTaskStartScheduler()函數中初始化爲portMAX_DELAY(portMAX_DELAY是一個portmacro.h中定義的宏,默認爲0xffffffffUL)

從上面原理提到可以知道xNextTaskUnblockTime 對於任務延時實現起到了很大的作用,也減少不定時掃描帶了的不確定開銷。具體實現,見官方源碼。

發佈了86 篇原創文章 · 獲贊 12 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章