RT Thread核心學習

2022-07-01 17:51:09 字數 3624 閱讀 1248

一、概述

二、執行緒的組成

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的核心由哪些構成呢?...