RTThread学习笔记1启动顺序与线程创建
目錄1. 啟動順序2. 堆范圍3. 線程創(chuàng)建3.1 線程代碼(入口函數(shù))3.2 線程控制塊3.3 線程棧4. 系統(tǒng)滴答時鐘5. GPIO驅(qū)動架構(gòu)操作IO6. 線程優(yōu)先級 & 時間片優(yōu)先級時間片優(yōu)先級搶占調(diào)度時間片輪詢調(diào)度7. 鉤子函數(shù)空閑線程系統(tǒng)調(diào)度鉤子函數(shù)參考文獻
1. 啟動順序
SystemInit()
$Sub$$main()
rtthread_startup()
rt_application_init()
main_thread_entry
$Super$$main用戶主函數(shù)
2. 堆范圍
自由分配的內(nèi)存(堆)起始地址為RAM的起始地址加上RW+ZI段后的地址區(qū)域。
編譯出的program size分為:
Code: 代碼段,存放程序的代碼部分
RO-data: 只讀數(shù)據(jù)段,存放程序中定義的常量
RW-data: 讀寫數(shù)據(jù)段,存放初始化為非0值的全局變量
ZI-data: 0數(shù)據(jù)段,存放未初始化得全局變量及初始化為0的變量
實際占用空間情況為:
RO Size包含了Code及RO-data,表示程序占用flash空間的大小
RW Size包含了RW-data及ZI-data,表示運行時占用RAM的大小
ROM Size包含了Code, RO Data和RW data,表示燒寫程序占用flash空間的大小
板子上電后默認從flash啟動,啟動之后會將RW段中的RW-data(初始化的全局變量)搬運到RAM中,但不會搬運RO段,即CPU的執(zhí)行代碼從flash中讀取,另外根據(jù)編譯器給出的ZI地址和大小,分配出ZI段,并將這塊RAM區(qū)域清零。動態(tài)內(nèi)存堆為未使用的RAM空間,應(yīng)用程序申請和釋放的內(nèi)存都來自該空間
char *ptr;
ptr = rt_malloc(10);
if (ptr != RT_NULL)
{
rt_memset(ptr, 0, 10);
rt_kprintf("malloc success\n");
rt_free(ptr);
ptr = RT_NULL;
}
3. 線程創(chuàng)建
RT-Thread中,線程由三部分組成:線程代碼(入口函數(shù))、線程控制塊、線程堆棧
3.1 線程代碼(入口函數(shù))
無限循環(huán)結(jié)構(gòu)
void thread_entry(void *parameter)
{
while(1)
{
/* 等待事件發(fā)生 */
/* 處理事件 */
}
}
順序執(zhí)行結(jié)構(gòu)
void thread_entry(void *parameter)
{
/* 事務(wù)1處理 */
/* 事務(wù)2處理 */
/* 事務(wù)3處理 */
}
3.2 線程控制塊
操作系統(tǒng)管理線程的一個數(shù)據(jù)結(jié)構(gòu)。存放線程的一些信息,比如優(yōu)先級、線程名稱、線程狀態(tài)等等,也包括線程與線程之間連接用的鏈表結(jié)構(gòu),線程等待時間集合等
struct rt_thread;
struct rt_thread *rt_thread_t;
3.3 線程棧
每個線程都有獨立的棧空間,線程切換時,系統(tǒng)會將當前線程的上下文保存在線程棧中,當線程要恢復(fù)運行時,再從線程棧中讀取上下文信息,恢復(fù)線程的運行。線程上下文是指線程執(zhí)行時的環(huán)境,各個變量和數(shù)據(jù)包括所有的寄存器變量,堆棧信息,內(nèi)存信息等。線程棧在形式上是一段連續(xù)的內(nèi)存空間,可以通過定義一個數(shù)組或者申請一段動態(tài)內(nèi)存來作為線程的棧
創(chuàng)建線程:
創(chuàng)建靜態(tài)線程
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)
創(chuàng)建動態(tài)線程
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))
啟動線程
rt_err_t rt_thread_startup(rt_thread_t thread)
調(diào)用此函數(shù)后創(chuàng)建的線程會被加入到線程的就緒隊列,執(zhí)行調(diào)度
rt_err_t thread_static_init()
{
rt_err_t result;
result = rt_thread_init(&thread,
"test",
thread_entry, RT_NULL,
&thread_stack[0], sizeof(thread_stack),
THREAD_PRIORITY, 10);
if (result == RT_EOK)
rt_thread_startup(&thread);
else
tc_stat(TC_STAT_END | TC_STAT_FAILED);
return result;
}
int thread_dynamic_init()
{
rt_thread_t tid;
tid = rt_thread_create("test",
thread_entry, RT_NULL,
THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
if (tid != RT_NULL)
rt_thread_startup(tid);
else
tc_stat(TC_STAT_END | TC_STAT_FAILED);
return 0;
}
rt_thread_delay(15); // 根據(jù)時鐘頻率決定。時鐘頻率100HZ,那么一次delay 10ms.此處就未150ms
rt_thread_sleep(15);
rt_thread_mdelay(15); // delay 15ms
區(qū)別:
資源分配形式不同:靜態(tài)線程的線程控制塊和線程棧是靜態(tài)分配的,而動態(tài)線程的這兩部分是運行時動態(tài)分配的
執(zhí)行效率:如果堆空間是片外RAM,那么動態(tài)線程的運行效率低于靜態(tài)線程。反之,如果都是片內(nèi)RAM,則沒有差別
4. 系統(tǒng)滴答時鐘
心跳時鐘由硬件定時器的定時中斷產(chǎn)生。稱之為系統(tǒng)滴答或者時鐘節(jié)拍。其頻率需要根據(jù)CPU的處理能力來決定。始終街拍使得內(nèi)核可以將線程延時若干個時鐘節(jié)拍,以及線程等待時間發(fā)生時,超時的依據(jù)。頻率越快,內(nèi)核函數(shù)介入系統(tǒng)運行的概率越大,內(nèi)核占用的處理器時間就越長,系統(tǒng)的負荷就越大。頻率越小,時間處理精度又不夠。在stm32平臺上一般設(shè)置系統(tǒng)滴答頻率為100HZ,即每個滴答的時間是10ms。在rtconfig.h中的RT_TICK_PER_SECOND宏,就是代表的HZ數(shù)
5. GPIO驅(qū)動架構(gòu)操作IO
#include <rt_device.h>
IO初始化
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
PIN_MODE_OUTPUT
PIN_MODE_INPUT
PIN_MODE_INPUT_PULLUP
PIN_MODE_INPUT_PULLDOWN
PIN_MODE_OUTPUT_OD
IO寫入
void rt_pin_write(rt_base_t pin, rt_base_t value)
PIN_HIGH
PIN_LOW
IO讀出
int rt_pin_read(rt_base_t pin)
首先通過看drv_gpio.c中的宏,得知我們設(shè)置的芯片有多少個腳。再看__STM32_PIN(2, E, 4).那么這里傳入2,就表示要操作PE4引腳
使用msh中的命令:list_thread。列出當前所有線程的棧使用情況
可以先將線程棧大小設(shè)置一個固定值(比如2048),在線程運行時通過該命令查看線程棧的使用情況,了解線程棧使用的實際情況,根據(jù)情況設(shè)置合理的大小。一般將線程棧最大使用量設(shè)置為70%
6. 線程優(yōu)先級 & 時間片
優(yōu)先級
分別描述了線程競爭處理器資源的能力和持有處理器時間長短的能力。RT-Thread最大支持256個優(yōu)先級,數(shù)值越小優(yōu)先級越高,0為最高優(yōu)先級,最低優(yōu)先級保留給空閑線程idle。可以通過rt_config.h中的RT_THREAD_PRIORITY_MAX宏,修改最大支持的優(yōu)先級。針對STM32默認設(shè)置最大支持32個優(yōu)先級。具體應(yīng)用中,線程總數(shù)不受限制,能創(chuàng)建的線程總數(shù)之和具體硬件平臺的內(nèi)存有關(guān)
時間片
只有在相同優(yōu)先級的就緒態(tài)線程中起作用,時間片起到約束線程單次運行時長的作用,其單位是一個系統(tǒng)街拍(OS Tick)
優(yōu)先級搶占調(diào)度
當有高優(yōu)先級線程處于就緒態(tài)后,就會發(fā)生任務(wù)調(diào)度
時間片輪詢調(diào)度
相同優(yōu)先級的線程,操作系統(tǒng)按照時間片大小輪流調(diào)度線程,時間片起到約束線程單次運行時長的作用。保證同優(yōu)先級任務(wù)輪流占有處理器
7. 鉤子函數(shù)
空閑線程
特殊的系統(tǒng)線程,具有最低的優(yōu)先級。系統(tǒng)中無其他就緒線程可運行時,調(diào)度器將調(diào)度到空閑線程。空閑線程負責一些系統(tǒng)資源回收以及將一些處于關(guān)閉態(tài)的線程從線程調(diào)度列表中移除的動作。空閑線程在形式上是一個無限循環(huán)結(jié)構(gòu),且永遠不被掛起。在RT-Thread實時操作系統(tǒng)中空閑線程向用戶提供了鉤子函數(shù),空閑線程鉤子函數(shù)可以在系統(tǒng)空閑的時候,執(zhí)行一些非緊急事務(wù),例如系統(tǒng)運行指示燈閃爍,CPU使用率統(tǒng)計等等
rt_err_t rt_thread_idle_sethook(void(*hook)(void))
rt_err rt_thread_idle_delhook(void(*hook)(void))
注意:
空閑線程是一個線程狀態(tài)永遠為就緒態(tài)的線程,所以鉤子函數(shù)中執(zhí)行的相關(guān)代碼必須保證空閑線程在任何時刻都不會被掛起,例如rt_thread_delay(), rt_sem_take()等可能會導致線程掛起的阻塞類函數(shù),都不能再鉤子函數(shù)中調(diào)用。
空閑線程可以設(shè)置多個鉤子函數(shù)(有最大限制)
系統(tǒng)調(diào)度鉤子函數(shù)
系統(tǒng)上下文切換是最普遍的時間,如果用戶想知道在某一個時刻發(fā)生了什么樣的線程切換,RT-Thread提供了一個系統(tǒng)調(diào)度鉤子函數(shù),這個鉤子函數(shù)在系統(tǒng)進行任務(wù)切換時運行,通過這個鉤子函數(shù),可以了解到系統(tǒng)任務(wù)調(diào)度時的信息
rt_scheduler_sethook(void(*hook)(struct rt_thread *from, struct rt_thread *to))
參考文獻
RT-Thread視頻中心內(nèi)核入門
RT-Thread文檔中心
本文作者: CrazyCatJack
本文鏈接: https://www.cnblogs.com/CrazyCatJack/p/14408835.html
版權(quán)聲明:本博客所有文章除特別聲明外,均采用BY-NC-SA許可協(xié)議。轉(zhuǎn)載請注明出處!
關(guān)注博主:如果您覺得該文章對您有幫助,可以點擊文章右下角推薦一下,您的支持將成為我最大的動力!
總結(jié)
以上是生活随笔為你收集整理的RTThread学习笔记1启动顺序与线程创建的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果证书申请步骤
- 下一篇: python基础之数据类型