今天給大家分享一點(diǎn)RT-Thread的基礎(chǔ)知識(shí)。
什么是線程?
人們?cè)谏钪刑幚韽?fù)雜問(wèn)題時(shí),慣用的方法就是分而治之,即把一個(gè)大問(wèn)題分解成多個(gè)相對(duì)簡(jiǎn)單、比較容易解決的小問(wèn)題,小問(wèn)題逐個(gè)被解決了,大問(wèn)題也就隨之解決了。同樣,在設(shè)計(jì)一個(gè)較為復(fù)雜的應(yīng)用程序時(shí),也通常把一個(gè)大型任務(wù)分解成多個(gè)小任務(wù),然后通過(guò)運(yùn)行這些小任務(wù),最終達(dá)到完成大任務(wù)的目的。
在裸機(jī)系統(tǒng)中, 系統(tǒng)的主體就是 main 函數(shù)里面順序執(zhí)行的無(wú)限循環(huán),這個(gè)無(wú)限循環(huán)里面 CPU 按照順序完成各種事情。在多線程系統(tǒng)中,我們根據(jù)功能的不同,把整個(gè)系統(tǒng)分割成一個(gè)個(gè)獨(dú)立的且無(wú)法返回的函數(shù),這個(gè)函數(shù)我們稱為線程。
線程由哪些部分組成?
RT-Thread 中的線程由三部分組成:線程代碼(函數(shù))、線程控制塊、線程堆棧。
線程棧
在一個(gè)裸機(jī)系統(tǒng)中, 如果有全局變量,有子函數(shù)調(diào)用,有中斷發(fā)生。那么系統(tǒng)在運(yùn)行的時(shí)候,全局變量放在哪里,子函數(shù)調(diào)用時(shí),局部變量放在哪里, 中斷發(fā)生時(shí),函數(shù)返回地址發(fā)哪里。
如果只是單純的裸機(jī)編程,它們放哪里我們不用管,但是如果要寫一個(gè) RTOS,這些種種環(huán)境參數(shù),我們必須弄清楚他們是如何存儲(chǔ)的。
在裸機(jī)系統(tǒng)中,他們統(tǒng)統(tǒng)放在一個(gè)叫棧的地方,棧是單片機(jī) RAM 里面一段連續(xù)的內(nèi)存空間,棧的大小一般在啟動(dòng)文件或者鏈接腳本里面指定, 最后由 C 庫(kù)函數(shù)_main 進(jìn)行初始化。
但是, 在多線程系統(tǒng)中,每個(gè)線程都是獨(dú)立的,互不干擾的,所以要為每個(gè)線程都分配獨(dú)立的??臻g,這個(gè)??臻g通常是一個(gè)預(yù)先定義好的全局?jǐn)?shù)組, 也可以是動(dòng)態(tài)分配的一段內(nèi)存空間,但它們都存在于 RAM 中。如:
staticrt_uint8_tled_stack[512];
線程棧其實(shí)就是一個(gè)預(yù)先定義好的全局?jǐn)?shù)據(jù),數(shù)據(jù)類型為rt_uint8_t,大小我們?cè)O(shè)置為 512。在 RT-Thread 中,凡是涉及到數(shù)據(jù)類型的地方, RTThread 都會(huì)將標(biāo)準(zhǔn)的 C 數(shù)據(jù)類型用 typedef 重新取一個(gè)類型名, 以“rt”前綴開頭。這些經(jīng)過(guò)重定義的數(shù)據(jù)類型放在 rtdef.h ,如:
線程控制塊
在 RT-Thread 中,線程控制塊由結(jié)構(gòu)體 struct rt_thread 表示,線程控制塊是操作系統(tǒng)用于管理線程的一個(gè)數(shù)據(jù)結(jié)構(gòu),它會(huì)存放線程的一些信息,例如優(yōu)先級(jí)、線程名稱、線程狀態(tài)等,也包含線程與線程之間連接用的鏈表結(jié)構(gòu),線程等待事件集合等,詳細(xì)定義如下(在rtdef.h中定義):
為led線程定義一個(gè)線程控制塊:
staticstructrt_threadled_thread;
線程函數(shù)
線程控制塊中的 entry 是線程的入口函數(shù),它是線程實(shí)現(xiàn)預(yù)期功能的函數(shù)。線程的入口函數(shù)由用戶設(shè)
計(jì)實(shí)現(xiàn),一般有以下兩種代碼形式:
無(wú)限循環(huán)模式:
在實(shí)時(shí)系統(tǒng)中,線程通常是被動(dòng)式的:這個(gè)是由實(shí)時(shí)系統(tǒng)的特性所決定的,實(shí)時(shí)系統(tǒng)通??偸堑却饨缡录陌l(fā)生,而后進(jìn)行相應(yīng)的服務(wù):
順序執(zhí)行或有限次循環(huán)模式:
如簡(jiǎn)單的順序語(yǔ)句、 do whlie() 或 for() 循環(huán)等,此類線程不會(huì)循環(huán)或不會(huì)永久循環(huán),可謂是 “一次性”線程,一定會(huì)被執(zhí)行完畢。在執(zhí)行完畢后,線程將被系統(tǒng)自動(dòng)刪除。
動(dòng)態(tài)線程與靜態(tài)線程
我們的用戶線程有兩種創(chuàng)建方式,一種是靜態(tài)線程,另一種是動(dòng)態(tài)線程。
創(chuàng)建靜態(tài)線程的函數(shù):
返回值為錯(cuò)誤代碼。
創(chuàng)建動(dòng)態(tài)線程的函數(shù):
返回值為線程控制塊 。
線程創(chuàng)建實(shí)例
創(chuàng)建一個(gè)靜態(tài)線程
1、確定線程棧
2、定義線程控制塊
3、創(chuàng)建線程函數(shù)。
#include #include #include /*靜態(tài)線程相關(guān)宏定義*/ #defineTHREAD_PRIORITY25/*優(yōu)先級(jí)*/ #defineSTACK_SIZE512/*棧大小*/ #defineTIMESLICE5/*時(shí)間片*/ /*線程三要素*/ staticrt_uint8_tstatic_thread_stack[STACK_SIZE];/*線程棧*/ staticstructrt_threadstatic_thread;/*線程控制塊*/ staticvoidstatic_thread_entry(void*parameter);/*線程入口函數(shù)*/ /*靜態(tài)線程入口函數(shù)*/ staticvoidstatic_thread_entry(void*parameter) { rt_uint32_ti=0; rt_kprintf("Thisisstaticthread!\n"); /*無(wú)限循環(huán)*/ while(1) { rt_kprintf("staticthreadcount:%d\r\n",++i); /*等待0.5s,讓出cpu權(quán)限,切換到其他線程*/ rt_thread_delay(500); } } /*主函數(shù)*/ intmain(void) { rt_err_tresult; /*創(chuàng)建靜態(tài)線程:優(yōu)先級(jí) 25 ,時(shí)間片 5個(gè)系統(tǒng)滴答,線程棧512字節(jié)*/ 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); /*創(chuàng)建成功則啟動(dòng)靜態(tài)線程*/ if(result==RT_EOK) { rt_thread_startup(&static_thread); } }
運(yùn)行結(jié)果為:
可見,在T-Thread中創(chuàng)建一個(gè)線程需要線程棧、線程控制塊與線程函數(shù)這三要素。除此之外,需要設(shè)置一個(gè)線程優(yōu)先級(jí),因?yàn)镽T-Thread的調(diào)度器是基于優(yōu)先級(jí)的搶占式調(diào)度算法。還需要設(shè)置一個(gè)時(shí)間片參數(shù),這個(gè)用于多個(gè)線程具有同等優(yōu)先級(jí)的情況下,采用時(shí)間片的輪轉(zhuǎn)調(diào)度算法進(jìn)行調(diào)度,這個(gè)值與時(shí)間節(jié)拍有關(guān),每一秒的節(jié)拍數(shù)可在rtconfig.h里進(jìn)行設(shè)置:
在這里我們只創(chuàng)建一個(gè)線程,所以時(shí)間片我們沒有用到,但也需要傳遞一個(gè)時(shí)間片的值給rt_thread_init函數(shù)。最后,在主函數(shù)里調(diào)用相關(guān)接口創(chuàng)建一個(gè)靜態(tài)線程,創(chuàng)建成功則啟動(dòng)該線程。
創(chuàng)建一個(gè)動(dòng)態(tài)線程
創(chuàng)建動(dòng)態(tài)線程與創(chuàng)建靜態(tài)線程類似:
#include #include #include /*動(dòng)態(tài)線程相關(guān)宏定義*/ #defineTHREAD_PRIORITY25/*優(yōu)先級(jí)*/ #defineSTACK_SIZE512/*棧大小*/ #defineTIMESLICE5/*時(shí)間片*/ /*線程三要素*/ staticrt_uint8_tdynamic_thread_stack[STACK_SIZE];/*線程棧*/ staticstructrt_threaddynamic_thread;/*線程控制塊*/ staticvoiddynamic_thread_entry(void*parameter);/*線程入口函數(shù)*/ /*動(dòng)態(tài)線程入口函數(shù)*/ staticvoiddynamic_thread_entry(void*parameter) { rt_uint32_ti; /*無(wú)限循環(huán)*/ while(1) { for(i=0;i5;?i++) ????????{ ????????????rt_kprintf("dynamic?thread?count:%d?\r\n",?i); ????????????/*?等待1s,讓出cpu權(quán)限,切換到其他線程?*/ ????????????rt_thread_delay(500); ????????} ????} } /*?主函數(shù)?*/ int?main(void) { ????rt_thread_t?tid;??//?動(dòng)態(tài)線程句柄 ????/*?創(chuàng)建動(dòng)態(tài)線程?:?優(yōu)先級(jí) 25 ,時(shí)間片 5個(gè)系統(tǒng)滴答,線程棧512字節(jié)?*/ ????tid?=?rt_thread_create("dynamic_thread", ????????????????????????????dynamic_thread_entry, ????????????????????????????RT_NULL, ????????????????????????????STACK_SIZE, ????????????????????????????THREAD_PRIORITY, ????????????????????????????TIMESLICE); ????/*?創(chuàng)建成功則啟動(dòng)動(dòng)態(tài)線程?*/ ????if?(tid?!=?RT_NULL) ????{ ????????rt_thread_startup(tid); ????}? }
運(yùn)行結(jié)果:
靜態(tài)線程VS動(dòng)態(tài)線程
上例中,從運(yùn)行結(jié)果上看,是沒有任何差別的!那么,我們?cè)趯?shí)際中如何抉擇?
使用靜態(tài)線程時(shí),必須先定義靜態(tài)的線程控制塊,并且定義好棧空間,然后調(diào)用rt_thread_init()函數(shù)來(lái)完成線程的初始化工作。采用這種方式,線程控制塊和堆棧占用的內(nèi)存會(huì)放在 RW/ZI 段,這段空間在編譯時(shí)就已經(jīng)確定,它不是可以動(dòng)態(tài)分配的,所以不能被釋放,而只能使用 rt_thread_detach()函數(shù)將該線程控制塊從對(duì)象管理器中脫離。
使用動(dòng)態(tài)定義方式 rt_thread_create()時(shí), RT-Thread 會(huì)動(dòng)態(tài)申請(qǐng)線程控制塊和堆棧空間。在編譯時(shí),編譯器是不會(huì)感知到這段空間的,只有在程序運(yùn)行時(shí), RT-Thread 才會(huì)從系統(tǒng)堆中申請(qǐng)分配這段內(nèi)存空間,當(dāng)不需要使用該線程時(shí),調(diào)用 rt_thread_delete()函數(shù)就會(huì)將這段申請(qǐng)的內(nèi)存空間重新釋放到內(nèi)存堆中。
這兩種方式各有利弊,靜態(tài)定義方式會(huì)占用 RW/ZI 空間,但是不需要?jiǎng)討B(tài)分配內(nèi)存,運(yùn)行時(shí)效率較高,實(shí)時(shí)性較好。動(dòng)態(tài)方式不會(huì)占用額外的 RW/ZI 空間,占用空間小,但是運(yùn)行時(shí)需要?jiǎng)討B(tài)分配內(nèi)存,效率沒有靜態(tài)方式高。
總的來(lái)說(shuō),這兩種方式就是空間和時(shí)間效率的平衡,可以根據(jù)實(shí)際環(huán)境需求選擇采用具體的分配方式。就像C編程中,何時(shí)使用動(dòng)態(tài)空間,何時(shí)使用靜態(tài)空間,也需要根據(jù)實(shí)際情況平衡選擇。
-
多線程
+關(guān)注
關(guān)注
0文章
276瀏覽量
19878 -
線程
+關(guān)注
關(guān)注
0文章
502瀏覽量
19613 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1249瀏覽量
39719
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論