一、概述
二、執行緒的組成
2.1、執行緒**(入口函式)
2.2、執行緒控制塊
2.3、執行緒棧
三、執行緒相關的api
3.1、執行緒的建立
3.2、狀態的切換
四、注意事項與補充
4.1、動態建立與靜態建立的優缺點比較?
4.2、系統滴答時鐘頻率的選取
4.3、執行緒棧大小分配的小策略
4.4、執行緒棧的資料具體是如何儲存的?
執行緒是rt-thread的核心部分,也是最基礎的功能,系統都是圍繞執行緒來構建的。
rt-thread中,執行緒由三部分組成:
1、執行緒**(入口函式)
2、執行緒控制塊
3、執行緒堆疊
執行緒**是我們實現某個功能的**實現,一般的入口函式都是無限迴圈結構,類似如下的**:
/* 執行緒1的入口函式 */
static void thread1_entry(void *parameter)
}當然也有順序執行結構,一些只需要執行一次,就不使用迴圈,執行完一次後就會被**,不再有效。
執行緒控制塊是作業系統用於管理執行緒的乙個資料結構,它會存放執行緒的一些資訊,例如優先順序、執行緒名稱、執行緒狀態等,也包括執行緒與執行緒之間連線用的鍊錶結構、執行緒等待事件集合等。
/*** thread structure
*/struct rt_thread //執行緒結構體
;typedef struct rt_thread *rt_thread_t; //執行緒結構體指標
rt-thread 每個執行緒都具有獨立的棧空間,當執行緒切換時,系統會將當前執行緒的上下文儲存到執行緒棧中,當執行緒要恢復時,再從對應的執行緒棧中讀取之前儲存的上下文資訊,從而恢復到被切換時的狀態,完整的恢復執行緒的執行。
執行緒上下文是指執行緒執行時的環境,具體來說,就是各個變數和資料報的所有暫存器變數、堆疊資訊、記憶體資訊等。(注:這裡要好好研究一下,比如具體儲存哪些,如何實現等,深究一下)
執行緒棧在形式上是一段連續的記憶體空間,可以通過定義乙個陣列或者申請一段動態記憶體來作為執行緒的棧。
3.1.1、建立靜態執行緒,初始化函式如下:
rt_err_t rt_thread_init(struct rt_thread *thread, //執行緒控制塊指標
const char *name, //執行緒名
void (*entry)(void *parameter), //入口函式
void *parameter, //入口函式引數
void *stack_start, //棧位址
rt_uint32_t stack_size, //棧大小(單位:位元組)
rt_uint8_t priority, //優先順序
rt_uint32_t tick) //時間片數(單位:系統滴答)
初始化前提,需要定義執行緒控制塊、棧(這裡一般是陣列)、入口函式,舉例如下:
/* 定義執行緒控制塊 */
static struct rt_thread led1_thread;
/* 定義線程式控制棧時要求rt_align_size個位元組對齊 */
align(rt_align_size)
/* 定義執行緒棧 */
static rt_uint8_t rt_led1_thread_stack[1024];
/* 函式宣告 */
static void led1_thread_entry(void* parameter);
3.1.2、建立動態執行緒,初始化函式如下:
//返回執行緒控制塊指標
rt_thread_t rt_thread_create(const char *name, //執行緒名字
void (*entry)(void *parameter), //執行緒入口函式
void *parameter, //入口函式引數
rt_uint32_t stack_size, //棧大小
rt_uint8_t priority, //優先順序
rt_uint32_t tick) //時間片
初始化前提,需要定義執行緒控制塊指標、入口函式,舉例如下:
/* 定義執行緒控制塊 */
static rt_thread_t led1_thread = rt_null;
/* 函式宣告 */
static void led1_thread_entry(void* parameter);
3.2.1、比較常用的是啟動函式,傳入的引數是執行緒控制塊指標。
/* 啟動執行緒,開啟排程 */
if (led1_thread != rt_null)
rt_thread_startup(led1_thread);
3.2.2、別的導致執行緒狀態切換的api如下:
3.3.1、空閒執行緒的鉤子函式
空閒鉤子函式是空閒執行緒的鉤子函式,如果設定了空閒鉤子函式,就可以在系統執行空閒執行緒時,自動執行空閒鉤子函式來做一些其他事情,比如系統指示燈等。api如下:
rt_err_t rt_thread_idle_sethook(void (*hook)(void)); //hook為自己定義的函式
rt_err_t rt_thread_idle_delhook(void (*hook)(void));
空閒執行緒的優先順序是最低的。最多可以設計四個空閒執行緒的鉤子函式(why?) 。
3.3.2、排程器的鉤子函式
在整個系統的執行時,系統都處於執行緒執行、中斷觸發 - 響應中斷、切換到其他執行緒,甚至是執行緒間的切換過程中,或者說系統的上下文切換是系統中最普遍的事件。有時使用者可能會想知道在乙個時刻發生了什麼樣的執行緒切換,可以通過呼叫下面的函式介面設定乙個相應的鉤子函式。在系統執行緒切換時,這個鉤子函式將被呼叫:
void rt_scheduler_sethook(void (*hook)(struct rt_thread* from, struct rt_thread* to));
鉤子函式 hook() 的宣告如下:
void hook(struct rt_thread* from, struct rt_thread* to);
注意: 請仔細編寫你的鉤子函式,稍有不慎將很可能導致整個系統執行不正常(在這個鉤子函式中,基本上不允許呼叫系統 api,更不應該導致當前執行的上下文掛起)。
排程器的鉤子函式只能設定乙個。
待續作業系統都存在乙個叫做「系統心跳」的時鐘,它是作業系統的最小時鐘單位,負責系統和時間相關的一些操作,這個心跳時鐘一般是由硬體定時器的中斷來產生的。
時鐘節拍使得核心可以將執行緒延時若干個整數時鐘節拍,以及執行緒等待事件時提供等待超時的依據。
系統的心跳時鐘也成為系統滴答或時鐘節拍,它的頻率,我們要根據cpu的處理能力來決定(比如72mhz的stm32f1,我們常設定每個滴答時間為10ms)。
頻率越快,核心函式介入系統執行的機率越大,核心占用處理器的時間就越長,系統的負荷越高,也就是說本該處理應用的計算資源更多的被核心占用。
但頻率越低,時間處理的精度又不夠,也可能會造成系統響應遲鈍。
RT Thread核心學習之執行緒管理
執行緒是作業系統能夠進行運算排程的最小單位,它被包含在程序之中,是程序中的實際運作單位,其本質是將複雜的應用 乙個程序 分解成多個小的 可排程的 序列化的程式單元,當合理的劃分任務並正確執行時,能夠讓系統滿足實時系統的效能及時間的要求。如下圖所示,嵌入式系統執行任務a,該任務是系統通過感測器採集資料...
RT Thread核心學習之時鐘管理
時鐘又稱為定時器,負責維護時間,防止程序壟斷cpu。作業系統需要通過時間來規範其任務的執行,其最小的時間單位是時鐘節拍 os tick 在rt thread中,時鐘節拍的長度可以根據rt tick per second的定義來調整,即通過改變時鐘頻率來調整時鐘節拍。實現方式 時鐘節拍由配置為中斷觸發...
Linux核心學習
交叉工具鏈 核心相關知識 linux系統的構成 使用者空間 核心空間 思考 為什麼劃分為兩個層次?目的其實是為保護作業系統,防止應用程式的異常導致作業系統崩潰。核心空間與使用者空間是程式執行的兩種不同狀態,通過系統呼叫和硬體中斷能夠完成從使用者空間到核心空間的轉移。那麼linux的核心由哪些構成呢?...