人們在生活中處理複雜問題時,慣用的方法就是分而治之
,即把一個大問題分解成多個相對簡單、比較容易解決的小問題,小問題逐個被解決了,大問題也就隨之解決了。一樣,在設計一個較爲複雜的應用程序時,也一般把一個大型任務分解成多個小任務,而後經過運行這些小任務,最終達到完成大任務的目的。git
在裸機系統中, 系統的主體就是 main 函數裏面順序執行的無限循環,這個無限循環裏面 CPU 按照順序完成各類事情。在多線程系統中,咱們根據功能的不一樣,把整個系統分割成一個個獨立的且沒法返回的函數,這個函數咱們稱爲線程
。github
RT-Thread 中的線程
由三部分組成:線程代碼(函數)、線程控制塊、線程堆棧。算法
在一個裸機系統中, 若是有全局變量,有子函數調用,有中斷髮生。那麼系統在運行的時候,全局變量放在哪裏,子函數調用時,局部變量放在哪裏, 中斷髮生時,函數返回地址發哪裏。編程
若是隻是單純的裸機編程,它們放哪裏咱們不用管,可是若是要寫一個 RTOS,這些種種環境參數,咱們必須弄清楚他們是如何存儲的。數組
在裸機系統中,他們通通放在一個叫棧的地方,棧是單片機 RAM 裏面一段連續的內存空間,棧的大小通常在啓動文件或者連接腳本里面指定, 最後由 C 庫函數_main 進行初始化。微信
可是, 在多線程系統中,每一個線程都是獨立的,互不干擾的,因此要爲每一個線程都分配獨立的棧空間,這個棧空間一般是一個預先定義好的全局數組
, 也能夠是動態分配的一段內存空間,但它們都存在於 RAM 中。 如:數據結構
static rt_uint8_t led_stack[512];
線程棧其實就是一個預先定義好的全局數據,數據類型爲rt_uint8_t,大小咱們設置爲 512。 在 RT-Thread 中,凡是涉及到數據類型的地方, RTThread 都會將標準的 C 數據類型用 typedef 從新取一個類型名, 以「rt」前綴開頭。這些通過重定義的數據類型放在 rtdef.h
,如:多線程
在 RT-Thread 中,線程控制塊由結構體 struct rt_thread
表示,線程控制塊是操做系統用於管理線程的一個數據結構,它會存放線程的一些信息,例如優先級、線程名稱、線程狀態等,也包含線程與線程之間鏈接用的鏈表結構,線程等待事件集合等,詳細定義以下(在rtdef.h
中定義): 函數
爲led線程定義一個線程控制塊:ui
static struct rt_thread led_thread;
線程控制塊中的 entry
是線程的入口函數,它是線程實現預期功能的函數。線程的入口函數由用戶設 計實現,通常有如下兩種代碼形式:
在實時系統中,線程一般是被動式的:這個是由實時系統的特性所決定的,實時系統一般老是等待外界事件的發生,然後進行相應的服務:
如簡單的順序語句、 do whlie() 或 for() 循環等,此類線程不會循環或不會永久循環,可謂是 「一次性」線程,必定會被執行完畢。在執行完畢後,線程將被系統自動刪除。
咱們的用戶線程有兩種建立方式,一種是靜態線程,另外一種是動態線程。
返回值爲錯誤代碼。
返回值爲線程控制塊 。
一、肯定線程棧
二、定義線程控制塊
三、建立線程函數。
#include <rtthread.h> #include <rtdevice.h> #include <board.h> /* 靜態線程相關宏定義 */ #define THREAD_PRIORITY 25 /* 優先級 */ #define STACK_SIZE 512 /* 棧大小 */ #define TIMESLICE 5 /* 時間片 */ /* 線程三要素 */ static rt_uint8_t static_thread_stack[STACK_SIZE]; /* 線程棧 */ static struct rt_thread static_thread; /* 線程控制塊 */ static void static_thread_entry(void* parameter); /* 線程入口函數 */ /* 靜態線程入口函數 */ static void static_thread_entry(void* parameter) { rt_uint32_t i = 0; rt_kprintf("This is static thread!\n"); /* 無限循環*/ while (1) { rt_kprintf("static thread count:%d \r\n", ++i); /* 等待0.5s,讓出cpu權限,切換到其餘線程 */ rt_thread_delay(500); } } /* 主函數 */ int main(void) { rt_err_t result; /* 建立靜態線程 : 優先級 25 ,時間片 5個系統滴答,線程棧512字節 */ result = rt_thread_init(&static_thread, "static_thread", static_thread_entry, RT_NULL, (rt_uint8_t*)&static_thread_stack[0], STACK_SIZE, THREAD_PRIORITY, TIMESLICE); /* 建立成功則啓動靜態線程 */ if (result == RT_EOK) { rt_thread_startup(&static_thread); } }
運行結果爲:
可見,在T-Thread中建立一個線程須要線程棧、線程控制塊與線程函數
這三要素。除此以外,須要設置一個線程優先級,由於RT-Thread的調度器是基於優先級的搶佔式調度算法。還須要設置一個時間片參數,這個用於多個線程具備同等優先級的狀況下,採用時間片的輪轉調度算法進行調度,這個值與時間節拍有關,每一秒的節拍數可在rtconfig.h
裏進行設置:
在這裏咱們只建立一個線程,因此時間片咱們沒有用到,但也須要傳遞一個時間片的值給rt_thread_init
函數。最後,在主函數裏調用相關接口建立一個靜態線程,建立成功則啓動該線程。
建立動態線程與建立靜態線程相似:
#include <rtthread.h> #include <rtdevice.h> #include <board.h> /* 動態線程相關宏定義 */ #define THREAD_PRIORITY 25 /* 優先級 */ #define STACK_SIZE 512 /* 棧大小 */ #define TIMESLICE 5 /* 時間片 */ /* 線程三要素 */ static rt_uint8_t dynamic_thread_stack[STACK_SIZE]; /* 線程棧 */ static struct rt_thread dynamic_thread; /* 線程控制塊 */ static void dynamic_thread_entry(void* parameter); /* 線程入口函數 */ /* 動態線程入口函數 */ static void dynamic_thread_entry(void* parameter) { rt_uint32_t i; /* 無限循環*/ while (1) { for (i = 0; i < 5; i++) { rt_kprintf("dynamic thread count:%d \r\n", i); /* 等待1s,讓出cpu權限,切換到其餘線程 */ rt_thread_delay(500); } } } /* 主函數 */ int main(void) { rt_thread_t tid; // 動態線程句柄 /* 建立動態線程 : 優先級 25 ,時間片 5個系統滴答,線程棧512字節 */ tid = rt_thread_create("dynamic_thread", dynamic_thread_entry, RT_NULL, STACK_SIZE, THREAD_PRIORITY, TIMESLICE); /* 建立成功則啓動動態線程 */ if (tid != RT_NULL) { rt_thread_startup(tid); } }
運行結果:
上例中,從運行結果上看,是沒有任何差異的!那麼,咱們在實際中如何抉擇?
使用靜態線程時,必須先定義靜態的線程控制塊,而且定義好棧空間,而後調用rt_thread_init()
函數來完成線程的初始化工做。採用這種方式,線程控制塊和堆棧佔用的內存會放在 RW/ZI
段,這段空間在編譯時就已經肯定,它不是能夠動態分配的,因此不能被釋放,而只能使用 rt_thread_detach()
函數將該線程控制塊從對象管理器中脫離。 使用動態定義方式 rt_thread_create()
時, RT-Thread 會動態申請線程控制塊和堆棧空間。在編譯時,編譯器是不會感知到這段空間的,只有在程序運行時, RT-Thread 纔會從系統堆中申請分配這段內存空間,當不須要使用該線程時,調用 rt_thread_delete()
函數就會將這段申請的內存空間從新釋放到內存堆中。
這兩種方式各有利弊,靜態定義方式會佔用 RW/ZI 空間,可是不須要動態分配內存,運行時效率較高,實時性較好。動態方式不會佔用額外的 RW/ZI 空間,佔用空間小,可是運行時須要動態分配內存,效率沒有靜態方式高。
總的來講,這兩種方式就是空間和時間效率的平衡,能夠根據實際環境需求選擇採用具體的分配方式。就像C編程中,什麼時候使用動態空間,什麼時候使用靜態空間,也須要根據實際狀況平衡選擇。
個人我的博客:https://zhengnianli.github.io/
個人微信公衆號:嵌入式大雜燴