RTThread學習筆記——對於執行緒的個人瞭解(二)
執行緒與執行緒就緒列表:
在RTT系統中,連結串列是一個相當重要的資料結構,RTT通過連結串列,來管理一些事物,例如說執行緒。
線上程控制塊中,有一個執行緒連結串列節點:
rt_list_t tlist; /**< the thread list */
這個節點可以將執行緒控制塊掛載到一些連結串列中。線上程建立之後,執行緒首先被新增到就緒列表中,就緒列表也被叫做執行緒優先順序表。
就緒列表實際上是一個 rt_list_t 的陣列。rt_list_t 是一個RTT定義的雙向連結串列型別,也就是說,這個陣列的每個元素都是一個雙向連結串列。
/*就緒列表陣列定義,在scheduler.c中*/ rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; /*RT_THREAD_PRIORITY_MAX定義,在rtconfig.h中*/ /*這裡定義為32,決定了執行緒的優先順序有多少個,這是RTT的優點之一*/ #define RT_THREAD_PRIORITY_MAX 32
這裡我們得知,陣列的下標對應了執行緒的優先順序,在RTT系統中,優先順序數字越小,邏輯優先順序越高。
在實際執行流程中,RTT通過rt_thread_startup來將執行緒插入到就緒列表/執行緒優先順序表中。
執行緒排程:
現在,我們擁有了執行緒優先順序表,接下來要實現的就是執行緒排程。
執行緒排程通過排程器來完成,排程器是RTOS系統的核心。
在排程器之前,先來看下RTT系統為了排程所設立的一個數——執行緒優先順序組。
#if RT_THREAD_PRIORITY_MAX > 32 /* Maximum priority level, 256 */ rt_uint32_t rt_thread_ready_priority_group; rt_uint8_t rt_thread_ready_table[32]; #else /* Maximum priority level, 32*/ rt_uint32_t rt_thread_ready_priority_group; #endif
在這裡,我們使用的MAX數小於等於32,所以使用的是else之後的定義。
執行緒優先順序組是來做什麼的?這裡舉一個荔枝:執行緒3準備好了,這時,優先順序組的第3位就會置1,然後執行緒會被插入優先順序表組(就緒列表)的第3個連結串列中。
然後在下一個系統週期中,排程器會從優先順序組中發現優先順序最高且置1的位,並且根據這個位從相應的優先順序表中讀取執行緒控制塊,並跳轉到這個執行緒上。具體識別位置並進行跳轉的機制是通過一個已經定義的陣列實現,在kservice.c中定義,這裡不詳細討論。
執行緒的狀態與需要程式設計事項:
RTT系統中的每個執行緒都有多種執行的狀態:
初始態:剛建立時的執行緒狀態
就緒態:執行緒在就緒列表中/優先順序表中,等待排程執行
執行態:顧名思義,正在執行的執行緒
掛起態:正在執行的執行緒被掛起,被阻塞延時,等待訊號時的狀態,此時執行緒不在就緒列表中
關閉態:執行緒結束
需注意什麼?
首先,線上程中,是不允許出現不讓出CPU的死迴圈的,執行緒必須在非活躍狀態下進入掛起或者阻塞,即使是優先順序非常高的執行緒,也必須讓出一定時間,或者在一段時間後結束,否則RTOS系統就失去了意義。
其次,無論是哪種方式程式設計,中斷都應該儘量要短,一般只是進行標記,太長的中斷有時對系統會產生巨大的不利影響。
最後,既然RTOS,就要考慮其實時性,這裡的實時是一個相對的指標,各個執行緒的實時響應時間都應符合具體的要求(例如響應時間小於5ms)。