欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

RT-Thread記錄(三、RT-Thread線程操作函數(shù))

矜辰所致 ? 來源:矜辰所致 ? 作者:矜辰所致 ? 2022-06-20 00:31 ? 次閱讀
前2課講完了RT-Thread開發(fā)環(huán)境,啟動流程,啟動以后當然是開始跑線程了,那么自然我們得學會如何創(chuàng)建線程以及線程的有關(guān)操作。

目錄

前言
一、RT-Thread線程操作函數(shù)
1.1 動態(tài)創(chuàng)建線程
1.2 靜態(tài)創(chuàng)建線程
1.3 啟動線程
線程創(chuàng)建的一個細節(jié)—創(chuàng)建和初始化?
句柄是什么?
1.4 刪除線程和脫離線程
1.5 掛起和恢復線程
1.6 其他線程輔助函數(shù)
1.6.1 獲得當前線程
1.6.2 讓出處理器資源
1.6.3 線程睡眠(延時函數(shù))
1.6.4 線程控制函數(shù)
1.6.5 設置和刪除空閑鉤子
1.6.6 設置調(diào)度器鉤子
二、RT-Thread線程創(chuàng)建示例
2.1 靜態(tài)創(chuàng)建線程示例
2.1 動態(tài)創(chuàng)建線程示例
三、RT-Thread線程管理簡析
3.1 線程調(diào)度的基本特點
3.2 線程控制塊
3.3 線程狀態(tài)
3.4 系統(tǒng)線程
結(jié)語

前言

前段時間寫完 RT-Thread 版本,開發(fā)環(huán)境,啟動流程后,停了好一段時間,因為完成了前面2課的講解,感覺直接用起來都問題不大了,為啥,因為RTOS的調(diào)度,線程通訊等機制,學習過FreeRTOS,看看RT-Thread官方的文檔說明,很多東西就很清楚了= =!以至于在寫本文的時候,都感覺,是不是太簡單了?

但是后來又想了想:

1、本系列博文的目的在于總結(jié)記錄,為的是以后在項目中使用起來,我可以直接參考自己總結(jié)的博文,而不是去翻官方的文檔資料
2、盡量使得沒有學習過 RT-Thread 的同學根據(jù)系列博文能夠?qū)?RT-Thread 有個認識,然后在一些細節(jié)的點上面有一定的理解,同時在遇到 RT-Thread 與 FreeRTOS不同的地方,會加以說明。
3、當初的FreeRTOS系列,真就是很隨意的按照自己學習測試的流程來走,對小白來說并不友好,回頭看起來,雖然我是真的畫了精力和事件去說明遇到的問題以及解決辦法,但是少了循序漸進的過程,整體也沒有一個好的框架體系,所以好像沒有幫到太多人(看的人不多哈= =?。?。所以在 RT-Thread 系列上面,該系統(tǒng)的還是得系統(tǒng)起來,即便有些東西簡單基礎,官方和網(wǎng)上文檔詳細,當做一個筆記,該記錄的還是得記錄!

好的,題外話說到這里,我們回到 RT-Thread 本身,上回我們已經(jīng)把啟動流程講清楚了,
上文的最后講到:整個系統(tǒng)就正常跑起來了,然后用戶運行自己想要做的事情,可以在 main 中設計自己的應用代碼,或者創(chuàng)建線程。

所以我們接下來當然得說說如何創(chuàng)建線程以及線程的一些操作。

本 RT-Thread 專欄記錄的開發(fā)環(huán)境:

RT-Thread記錄(一、RT-Thread 版本、RT-Thread Studio開發(fā)環(huán)境 及 配合CubeMX開發(fā)快速上手)

RT-Thread記錄(二、RT-Thread內(nèi)核啟動流程 — 啟動文件和源碼分析

一、RT-Thread線程操作函數(shù)

RT-Thread線程操作包含:創(chuàng)建 / 初始化線程、啟動線程、運行線程、刪除 / 脫離線程。

1.1 動態(tài)創(chuàng)建線程

函數(shù)比較簡單,具體的看注釋就好(本文余下的函數(shù)介紹類似,看注釋):

/*
demo,用來接收動態(tài)線程返回的句柄
比如 led2_thread  = rt_thread_create(......);
*/
static rt_thread_t led2_thread = RT_NULL; 

#ifdef RT_USING_HEAP      					//定義使用了HEAP才能動態(tài)創(chuàng)建線程
/*
參數(shù)的含義,放在上面看起來更加方便,要不然太長了
1、線程的名稱;線程名稱的最大長度由 rtconfig.h 中的宏 RT_NAME_MAX 指定,多余部分會被自動截掉
2、線程入口函數(shù)
3、線程入口函數(shù)參數(shù),沒有就用 RT_NULL
4、線程棧大小,單位是字節(jié)
5、線程的優(yōu)先級。優(yōu)先級范圍根據(jù)系統(tǒng)配置情況(rtconfig.h 中的 RT_THREAD_PRIORITY_MAX 宏定義),
如果支持的是 256 級優(yōu)先級,那么范圍是從 0~255,數(shù)值越小優(yōu)先級越高,0 代表最高優(yōu)先級
6、線程的時間片大小。時間片(tick)的單位是操作系統(tǒng)時鐘節(jié)拍。
當系統(tǒng)中存在相同優(yōu)先級線程時,這個參數(shù)指定線程一次調(diào)度能夠運行的最大時間長度。
這個時間片運行結(jié)束時,調(diào)度器自動選擇下一個就緒態(tài)的同優(yōu)先級線程進行運行
返回值:
線程創(chuàng)建成功,返回線程句柄
線程創(chuàng)建失敗,返回RT_BULL 
*/
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)

1.2 靜態(tài)創(chuàng)建線程

static struct rt_thread led1_thread;   //demo,用戶定義的線程句柄
static char led1_thread_stack[256];    //demo,用戶定義的靜態(tài)線程大小
/*
參數(shù)的含義
1、線程句柄。線程句柄由用戶提供出來,并指向?qū)木€程控制塊內(nèi)存地址,上面的led1_thread。
2、線程的名稱;線程名稱的最大長度由 rtconfig.h 中定義的 RT_NAME_MAX 宏指定,多余部分會被自動截掉
3、線程入口函數(shù)
4、線程入口函數(shù)參數(shù),沒有就用 RT_NULL
5、線程棧起始地址,根據(jù)上面定義就是 &led1_thread_stack[0],
6、線程棧大小,單位是字節(jié)。根據(jù)上面定義就是 sizeof(led1_thread_stack),
在大多數(shù)系統(tǒng)中需要做??臻g地址對齊(例如 ARM 體系結(jié)構(gòu)中需要向 4 字節(jié)地址對齊)
7、線程的優(yōu)先級。優(yōu)先級范圍根據(jù)系統(tǒng)配置情況(rtconfig.h 中的 RT_THREAD_PRIORITY_MAX 宏定義),
如果支持的是 256 級優(yōu)先級,那么范圍是從 0~255,數(shù)值越小優(yōu)先級越高,0 代表最高優(yōu)先級
8、線程的時間片大小。時間片(tick)的單位是操作系統(tǒng)的時鐘節(jié)拍。
當系統(tǒng)中存在相同優(yōu)先級線程時,這個參數(shù)指定線程一次調(diào)度能夠運行的最大時間長度。
這個時間片運行結(jié)束時,調(diào)度器自動選擇下一個就緒態(tài)的同優(yōu)先級線程進行運行
返回值:
線程創(chuàng)建成功,返回RT_EOK
線程創(chuàng)建失敗,返回RT_ERROR 	
*/
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);

這里需要說明一下,為什么用戶定義一個 char 類型的數(shù)組可以作為線程??臻g呢?

因為申請一個全局變量的數(shù)組,本質(zhì)就是開辟了一段連續(xù)的內(nèi)存空間!這是用戶申請的,所以在編譯的時候就被確定分配好了,這段內(nèi)存空間申請出來,通過rt_thread_init函數(shù),就分配給了這個線程使用。

如果知道了上面的話,但是還不能理解內(nèi)存空間和線程有什么關(guān)系的時候,這個就得慢慢來……簡單來說就是,線程運行需要占用一段內(nèi)存空間,這段內(nèi)存空間每個線程的都不一樣,他們是用來線程運行的時候,函數(shù)調(diào)用線程切換保存現(xiàn)場用的。
反正先記住必須給每個線程單獨的一片內(nèi)存空間,RTOS才能正常運行,所有的RTOS都是。
動態(tài)創(chuàng)建同樣的意思,只不過你看不到,由內(nèi)核函數(shù)自動處理了就沒那么直觀。


在上面示例代碼中,256個char類型的數(shù)組,就是占用256個字節(jié)(char類型占用1個字節(jié)),所以最后分配給線程的空間就是256個字節(jié)。

1.3 啟動線程

創(chuàng)建完線程并不代表線程就運行了,在RT-Thread稱為初始狀態(tài),要跑起來需要人為的給他“開”一下,這里與FreeRTOS創(chuàng)建任務后是不同的,F(xiàn)reeRTOS是直接創(chuàng)建完成就開始運行參與調(diào)度了。

創(chuàng)建的線程狀態(tài)處于初始狀態(tài),并未進入就緒線程的調(diào)度隊列,我們可以在線程創(chuàng)建成功后調(diào)用rt_thread_startup函數(shù)接口讓該線程進入就緒態(tài):

/*
static rt_thread_t led2_thread = RT_NULL;
static struct rt_thread led1_thread;
上面的兩個demo就是:
rt_thread_startup(&led1_thread);
rt_thread_startup(led2_thread);
*/
rt_err_t rt_thread_startup(rt_thread_t thread);

這里又有一個小細節(jié)需要說明一下,動態(tài)和靜態(tài)創(chuàng)建線程的rt_thread_startup使用的小區(qū)別!

上面代碼的注釋中,兩個Demo:
一個是rt_thread_startup(&led1_thread);(靜態(tài))
一個是rt_thread_startup(led2_thread);(動態(tài))

靜態(tài)線程為什么需要取地址,動態(tài)可以直接用,不仔細看的話還不一定發(fā)現(xiàn)這個問題, 其實從他們的定義就已經(jīng)不同了,只不過rt_thread_t 和rt_thread 一眼看去還真可能傻傻分不清楚 = =!以前我剛用的時候也在這里迷糊了一會


static struct rt_thread led1_thread 靜態(tài)類型為struct rt_thread 類型就是線程控制塊結(jié)構(gòu)體
static rt_thread_t led2_thread 動態(tài)類型為rt_thread_t 類型是一個指針,如下解釋:

rt_thread_t這個類型他是經(jīng)過 typedef 重名命的:

pYYBAGKugY6AFcjLAAA33jozQiM609.png

所以回到開始的問題,搞清楚了rt_thread_startup 函數(shù)的參數(shù)是線程控制塊結(jié)構(gòu)體指針, 再結(jié)合動態(tài)靜態(tài)創(chuàng)建線程的線程句柄定義,這么問題就清楚了!明白了這個,那么這里又可以說明一個細節(jié)問題!如下

線程創(chuàng)建的一個細節(jié)—創(chuàng)建和初始化?

在文中,我介紹API使用的標題是“動態(tài)創(chuàng)建線程” 和“靜態(tài)創(chuàng)建線程”,個人認為看上去好理解,也沒問題,但是這里注意官方的用語:

動態(tài)是 – 創(chuàng)建和刪除線程
靜態(tài)是 – 初始化和脫離線程

說白了都是新建線程,但是用詞卻不一樣,為什么動態(tài)用創(chuàng)建,而靜態(tài)用初始化呢?帶著疑問我們回頭再去看看兩種方式的不同。
在使用rt_thread_init之前,我們需要定義兩個東西,一個結(jié)構(gòu)體,一個數(shù)組:

static struct rt_thread led1_thread;   //demo,用戶定義的線程句柄
static char led1_thread_stack[256];    //demo,用戶定義的靜態(tài)線程大小

在編譯的時候,這個結(jié)構(gòu)體和數(shù)組,就被分配了一定的內(nèi)存空間,這段空間默認一般是初始化為0,就是空間給你留著了,但是等著你去放數(shù)據(jù)。不管在程序后面使不使用rt_thread_init,這段空間都已經(jīng)存在了的! 這樣來說,調(diào)用rt_thread_init只是對已經(jīng)存在的一段內(nèi)存空間的賦值,對一個存在的東西的設置,不就是叫做 初始化嗎。所以使用靜態(tài)的創(chuàng)建嚴格的來說,更應該稱之為初始化線程!

而在使用rt_thread_create之前,我們只需要定義一個rt_thread_t 類型的指針,初始化是NULL就沒有了,只有在調(diào)用rt_thread_create成功之后,才會開辟出一塊存放線程控制塊的內(nèi)存空間,從無到有的一個過程,所以叫做 創(chuàng)建。

不得不佩服,官方還是用詞嚴謹,其實想想也能更好的理解函數(shù)功能!

句柄是什么?

講到這里,為了讓有些小伙伴更容易看懂,我們再插一個細節(jié),我們經(jīng)常聽到返回句柄,函數(shù)句柄,任務句柄,那么句柄是什么?

記住一句話:句柄其實就是指針,它是指向指針的指針。

在我們的rt_thread_create函數(shù)中,如果成功返回值是 線程句柄,類型為rt_thread_t ,我們前面又講過rt_thread_t 是一個結(jié)構(gòu)體指針,這個結(jié)構(gòu)體是線程控制塊結(jié)構(gòu)體,所以 在上面示例代碼中返回句柄的意思 ,就是返回了一個指針,這個指針指向線程控制塊。

(如果指針,指向指針的指針不明白,這是C語言基礎知識,可以查看相關(guān)資料,我有一篇博文也提到過一二:C語言學習點滴筆記 中 4、指針: 一種特殊的變量 和 多元指針,指向指針的指針)

1.4 刪除線程和脫離線程

針對上面動態(tài)靜態(tài)方法創(chuàng)建的線程,RT-Thread 有不同的刪除函數(shù):
對于使用rt_thread_create動態(tài)創(chuàng)建的線程,我們使用rt_thread_delete函數(shù),如下:

/*
參數(shù):thread 	要刪除的線程句柄
返回值:
RT_EOK 		刪除線程成功
-RT_ERROR 	刪除線程失敗
*/
rt_err_t rt_thread_delete(rt_thread_t thread);

調(diào)用該函數(shù)后,線程對象將會被移出線程隊列并且從內(nèi)核對象管理器中刪除,線程占用的堆??臻g也會被釋放。實際上,用 rt_thread_delete() 函數(shù)刪除線程接口,僅僅是把相應的線程狀態(tài)更改為 RT_THREAD_CLOSE 狀態(tài),然后放入到 rt_thread_defunct 隊列中;而真正的刪除動作(釋放線程控制塊和釋放線程棧)需要到下一次執(zhí)行空閑線程時,由空閑線程完成最后的線程刪除動作。

對于使用rt_thread_init 靜態(tài)創(chuàng)建的線程,我們使用rt_thread_detach 函數(shù),如下:

/*
參數(shù):線程句柄,它應該是由 rt_thread_init 進行初始化的線程句柄。
返回值:
RT_EOK 		線程脫離成功
-RT_ERROR  	線程脫離失敗
*/
rt_err_t rt_thread_detach (rt_thread_t thread);

官方在介紹rt_thread_detach有一句話,同樣,線程本身不應調(diào)用這個接口脫離線程本身。這句話我理解就是不管動態(tài)刪除還是靜態(tài)刪除,不能在線程函數(shù)中自己把自己刪除。
這里也與FreeRTOS任務后不同,F(xiàn)reeRTOS可以直接在任務中調(diào)用函數(shù)刪除自己。

但是需要特別說明的是,在 RT-Thread 中執(zhí)行完畢的線程系統(tǒng)會自動將其刪除!用戶無需多余操作,如何理解呢,看下面的例子:

我們一般線程函數(shù)都是死循環(huán),通過延時釋放CPU控制權(quán),比如:

static void led1_thread_entry(void *par){
    while(1){   		
        //do_something
        rt_thread_mdelay(100);
    }
}

我們需要刪除的線程往往只是為了做某一件事,某一次特殊的事情,比如:

static void this_is_a_need_delete_task(void *par){ 	
  			//do_one_time_thing
}

其實這個線程是為了某一件特殊事情而創(chuàng)建的,它是需要刪除的,我們并不需要做任何特殊處理,因為執(zhí)行是沒有循環(huán)的,執(zhí)行完成以后,RT-Thread 內(nèi)核會自動把線程刪除??!

1.5 掛起和恢復線程

線程掛起和恢復,在官方有單獨的說明:

poYBAGKugY-AHofUAADH8yWiUeU475.png

既然官方強烈不建議在程序中使用該接口,我們這里就不說明了,因為以應用為主,我們就不去用了。

需要說明的一點是,這里和FreeRTOS也是不同的,F(xiàn)reeRTOS用戶可以隨意用,最典型的就是使一段代碼進入臨界區(qū)掛起其他任務。

1.6 其他線程輔助函數(shù)

其他的線程輔助函數(shù),除了線程睡眠函數(shù),其他的在一般的應用中都可以不需要。所以我們簡單的過一遍,引用一下官方的介紹。如果后期應用的時候有用到,再來加以詳細說明:

1.6.1 獲得當前線程

在程序的運行過程中,相同的一段代碼可能會被多個線程執(zhí)行,在執(zhí)行的時候可以通過下面的函數(shù)接口獲得當前執(zhí)行的線程句柄,把下面的函數(shù)加在這段代碼中的,哪個線程調(diào)用就返回哪個線程句柄:

/*
返回值
thread 	當前運行的線程句柄
RT_NULL 	失敗,調(diào)度器還未啟動
*/
rt_thread_t rt_thread_self(void);

1.6.2 讓出處理器資源

rt_err_t rt_thread_yield(void);

調(diào)用該函數(shù)后,當前線程首先把自己從它所在的就緒優(yōu)先級線程隊列中刪除,然后把自己掛到這個優(yōu)先級隊列鏈表的尾部,然后激活調(diào)度器進行線程上下文切換(如果當前優(yōu)先級只有這一個線程,則這個線程繼續(xù)執(zhí)行,不進行上下文切換動作)。

1.6.3 線程睡眠(延時函數(shù))

線程睡眠,直白點說,就是延時函數(shù),只不過RTOS中的延時函數(shù),是會釋放CPU使用權(quán)的,釋放CPU使用權(quán),就等于線程睡眠了。

/*
參數(shù):tick/ms 	
線程睡眠的時間:sleep/delay 的傳入?yún)?shù) tick 以 1 個 OS Tick 為單位 ;
mdelay 的傳入?yún)?shù) ms 以 1ms 為單位;
返回
RT_EOK 	操作成功,一般不需要
*/
rt_err_t rt_thread_sleep(rt_tick_t tick);
rt_err_t rt_thread_delay(rt_tick_t tick);
rt_err_t rt_thread_mdelay(rt_int32_t ms);

1.6.4 線程控制函數(shù)

/*
參數(shù)說明:
1、thread 	線程句柄
2、cmd 	指示控制命令
cmd 當前支持的命令包括:
?RT_THREAD_CTRL_CHANGE_PRIORITY:動態(tài)更改線程的優(yōu)先級;
?RT_THREAD_CTRL_STARTUP:開始運行一個線程,等同于 rt_thread_startup() 函數(shù)調(diào)用;
?RT_THREAD_CTRL_CLOSE:關(guān)閉一個線程,
等同于 rt_thread_delete() 或 rt_thread_detach() 函數(shù)調(diào)

用。
3、arg 	控制參數(shù)
返回值:
RT_EOK 		控制執(zhí)行正確
-RT_ERROR 	失敗
*/
rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void* arg);

1.6.5 設置和刪除空閑鉤子

空閑鉤子函數(shù)是空閑線程的鉤子函數(shù)(不要和調(diào)度器鉤子函數(shù)搞混了),如果設置了空閑鉤子函數(shù),就可以在系統(tǒng)執(zhí)行空閑線程時,自動執(zhí)行空閑鉤子函數(shù)來做一些其他事情,比如系統(tǒng)指示燈。設置 / 刪除空閑鉤子的接口如下:

/*
參數(shù):
hook 	設置的鉤子函數(shù),在函數(shù)中實現(xiàn)一些操作,但是不要有掛起操作
返回值:
RT_EOK 	設置成功
-RT_EFULL 	設置失敗
*/
rt_err_t rt_thread_idle_sethook(void (*hook)(void));
rt_err_t rt_thread_idle_delhook(void (*hook)(void));

官方有一段注意說明如下:

pYYBAGKugY-ABrtwAACBToveT2k280.png

1.6.6 設置調(diào)度器鉤子

在整個系統(tǒng)的運行時,系統(tǒng)都處于線程運行、中斷觸發(fā) - 響應中斷、切換到其他線程,甚至是線程間的切換過程中,或者說系統(tǒng)的上下文切換是系統(tǒng)中最普遍的事件。有時用戶可能會想知道在一個時刻發(fā)生了什么樣的線程切換,可以通過調(diào)用下面的函數(shù)接口設置一個相應的鉤子函數(shù)。在系統(tǒng)線程切換時,這個鉤子函數(shù)將被調(diào)用:

/*
參數(shù):
hook 	表示用戶定義的鉤子函數(shù)指針
*/
void rt_scheduler_sethook(void (*hook)(struct rt_thread* from, struct rt_thread* to));
/*
鉤子函數(shù) hook() 的聲明
參數(shù)說明:
1、from 	表示系統(tǒng)所要切換出的線程控制塊指針
2、to 	表示系統(tǒng)所要切換到的線程控制塊指針
*/
void hook(struct rt_thread* from, struct rt_thread* to);

————————————————
版權(quán)聲明:本文為CSDN博主「矜辰所致」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_42328389/article/details/123440027

注:請仔細編寫你的鉤子函數(shù),稍有不慎將很可能導致整個系統(tǒng)運行不正常(在這個鉤子函數(shù)中,基本上不允許調(diào)用系統(tǒng) API,更不應該導致當前運行的上下文掛起)。

二、RT-Thread線程創(chuàng)建示例

雖然上面介紹了有一部分的線程操作函數(shù),但是正常需要也就前面幾個,記住線程創(chuàng)建,啟動,一般的應用就足夠了,其他的一些輔助函數(shù)在實際中有很多情況是出了問題以后找 bug 的時候才會想起來。

所以我們演示起來也很簡單,還記得在 RT-Thread記錄 第一篇文章中:

RT-Thread記錄(一、RT-Thread 版本、RT-Thread Studio開發(fā)環(huán)境 及 配合CubeMX開發(fā)快速上手)

在上面博文的最后一節(jié):3.3 創(chuàng)建一個跑馬燈任務 我上傳了一段源碼,這里我就不再重復上一邊了,我們直接通過截圖說明的方式講解下示例:

2.1 靜態(tài)創(chuàng)建線程示例

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16

2.1 動態(tài)創(chuàng)建線程示例

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16

三、RT-Thread線程管理簡析

經(jīng)過上面的說明,我們其實能夠使用 RT-Thread 對于的函數(shù)創(chuàng)建線程進行一般的設計了,但是為了加深對RT-Thread的理解,我們還得聊聊 RT-Thread線程管理。

這一塊在官網(wǎng)其實有詳細的說明,官方的鏈接如下:RT-Thread官方文檔 RT-Thread內(nèi)核線程管理

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16

3.1 線程調(diào)度的基本特點

我這邊按照自己的理解認知記錄幾個重要的點:

1、RT-Thread 的線程調(diào)度器是搶占式的,主要的工作就是從就緒線程列表中查找最高優(yōu)先級線程,保證最高優(yōu)先級的線程能夠被運行,最高優(yōu)先級的任務一旦就緒,總能得到 CPU 的使用權(quán)。

調(diào)度器開啟以后,就不停的在查詢列表,所有的線程根據(jù)優(yōu)先級,狀態(tài),在列表中排序,調(diào)度器總是找到排序“第一位”的線程執(zhí)行。RTOS的核心就是鏈表,這個有時間會單獨的介紹。

2、當一個運行著的線程使一個比它優(yōu)先級高的線程滿足運行條件,當前線程的 CPU 使用權(quán)就被剝奪了,或者說被讓出了,高優(yōu)先級的線程立刻得到了 CPU 的使用權(quán)。

如果是中斷服務程序使一個高優(yōu)先級的線程滿足運行條件,中斷完成時,被中斷的線程掛起,優(yōu)先級高的線程開始運行。

還是上面說到的調(diào)度器的作用,使得高優(yōu)先級的能夠及時執(zhí)行。

3、當調(diào)度器調(diào)度線程切換時,先將當前線程上下文保存起來,當再切回到這個線程時,線程調(diào)度器將該線程的上下文信息恢復。
RT-Thread 線程具有獨立的棧,當進行線程切換時,會將當前線程的上下文存在棧中,當線程要恢復運行時,再從棧中讀取上下文信息,進行恢復。

要理解上面的話,推薦一篇博文:
FreeRTOS記錄(三、FreeRTOS任務調(diào)度原理解析_Systick、PendSV、SVC)
雖然說的是FreeRTOS的,但是都是基于Cortex-M內(nèi)核的,原理機制類似。

4、每個線程都有時間片這個參數(shù),但時間片僅對優(yōu)先級相同的就緒態(tài)線程有效。

時間片只有在優(yōu)先級相同的線程間會根據(jù)用戶的設置進行對應的分配。

5、線程中不能陷入死循環(huán)操作,必須要有讓出 CPU 使用權(quán)的動作,如循環(huán)中調(diào)用延時函數(shù)或者主動掛起。

使用rtos延時函數(shù),是實際使用最常見的一種方式,切記,delay是需要在while(1){}大括號里面的:

pYYBAGKugZCAFA24AAA7uJ1Dcwk673.png

3.2 線程控制塊

在我們上面介紹線程操作函數(shù)的時候,經(jīng)常提到一個詞語,線程控制塊,線控控制塊結(jié)構(gòu)體,RT-Thread 內(nèi)核對于線程的管理,都是基于這個結(jié)構(gòu)體進行的。這里我們先有個基本的認識,如果真的深入探討,還是要說到RTOS的鏈表,需要單獨的開篇博文說明。

我們現(xiàn)在要了解的是,內(nèi)核對于線程的管理是通過這個線程控制塊結(jié)構(gòu)體,里面包括 RT-Thread線程所有的“屬性”,對這些屬性的查看,修改就可以對實現(xiàn)對這個線程的管理控制。

我們來看看控制塊結(jié)構(gòu)體(不是直接復制官網(wǎng)的哦?。?/p>

/** * Thread structure */struct rt_thread{    /* rt object */    char        name[RT_NAME_MAX];        /**< the name of thread 線程名稱*/    rt_uint8_t  type;                     /**< type of object 對象類型*/    rt_uint8_t  flags;                    /**< thread's flags 標志位*/#ifdef RT_USING_MODULE    void       *module_id;                /**< id of application module */#endif    rt_list_t   list;                     /**< the object list 對象列表*/    rt_list_t   tlist;                    /**< the thread list 線程列表*/    /* stack point and entry 棧指針與入口指針*/    void       *sp;                       /**< stack point 棧指針*/    void       *entry;                    /**< entry 入口函數(shù)指針*/    void       *parameter;                /**< parameter 參數(shù)*/    void       *stack_addr;               /**< stack address 棧地址指針 */    rt_uint32_t stack_size;               /**< stack size 棧大小*/    /* error code */    rt_err_t    error;                    /**< error code 線程錯誤代碼*/    rt_uint8_t  stat;                     /**< thread status 線程狀態(tài) */#ifdef RT_USING_SMP           		 /*多核相關(guān)支持,我們這里就一個M3內(nèi)核*/    rt_uint8_t  bind_cpu;                /**< thread is bind to cpu */    rt_uint8_t  oncpu;                   /**< process on cpu` */    rt_uint16_t scheduler_lock_nest;        /**< scheduler lock count */    rt_uint16_t cpus_lock_nest;             /**< cpus lock count */    rt_uint16_t critical_lock_nest;         /**< critical lock count */#endif /*RT_USING_SMP*/    /* priority 優(yōu)先級*/    rt_uint8_t  current_priority;           /**< current priority 當前優(yōu)先級 */    rt_uint8_t  init_priority;              /**< initialized priority 初始優(yōu)先級 */#if RT_THREAD_PRIORITY_MAX > 32    rt_uint8_t  number;    rt_uint8_t  high_mask;#endif    rt_uint32_t number_mask;#if defined(RT_USING_EVENT)                /*使用事件集*/    /* thread event */    rt_uint32_t event_set;    rt_uint8_t  event_info;#endif#if defined(RT_USING_SIGNALS)							    rt_sigset_t     sig_pending;        /**< the pending signals */    rt_sigset_t     sig_mask;           /**< the mask bits of signal */#ifndef RT_USING_SMP					/*多核相關(guān)支持,我們這里就一個M3內(nèi)核*/    void            *sig_ret;           /**< the return stack pointer from signal */#endif    rt_sighandler_t *sig_vectors;       /**< vectors of signal handler */    void            *si_list;           /**< the signal infor list */#endif    rt_ubase_t  init_tick;              /**< thread's initialized tick 線程初始化計數(shù)值*/    rt_ubase_t  remaining_tick;         /**< remaining tick 線程剩余計數(shù)值*/    struct rt_timer thread_timer;       /**< built-in thread timer 內(nèi)置線程定時器*/     /**< cleanup function when thread exit      線程退出清除函數(shù)     cleanup 函數(shù)指針指向的函數(shù),會在線程退出的時候,被idle 線程回調(diào)一次,     執(zhí)行用戶的清理現(xiàn)場工作。     */    void (*cleanup)(struct rt_thread *tid);      /* light weight process if present */#ifdef RT_USING_LWP    void        *lwp;#endif    rt_ubase_t user_data;      /**< private user data beyond this thread  用戶數(shù)據(jù)*/};typedef struct rt_thread *rt_thread_t;

3.3 線程狀態(tài)

線程的狀態(tài)我們借用官方的幾張圖,加以說明:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16

來看看 RT-Thread 的任務狀態(tài):

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16

在上圖中除了今天我們介紹的線程操作函數(shù),還有一些函數(shù)還沒有介紹過,比如rt_sem_take(),rt_mutex_take(),rt_mb_recv() ,這是我們后期會介紹到的關(guān)于線程間通信的一些信號量,互斥量相關(guān)的函數(shù)。

作為對比,再來看看FreeRTOS 的任務狀態(tài):

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_1,color_FFFFFF,t_70,g_se,x_16

3.4 系統(tǒng)線程

在 RT-Thread 內(nèi)核中的系統(tǒng)線程有空閑線程和主線程。

空閑線程 IDLE線程:

空閑線程是系統(tǒng)創(chuàng)建的最低優(yōu)先級的線程,線程狀態(tài)永遠為就緒態(tài)。當系統(tǒng)中無其他就緒線程存在時,調(diào)度器將調(diào)度到空閑線程,它通常是一個死循環(huán),且永遠不能被掛起。這點其實所有RTOS都是一樣的。

但是,空閑線程在 RT-Thread 也有著它的特殊用途:

若某線程運行完畢,系統(tǒng)將自動刪除線程:自動執(zhí)行 rt_thread_exit() 函數(shù),先將該線程從系統(tǒng)就緒隊列中刪除,再將該線程的狀態(tài)更改為關(guān)閉狀態(tài),不再參與系統(tǒng)調(diào)度,然后掛入 rt_thread_defunct 僵尸隊列(資源未回收、處于關(guān)閉狀態(tài)的線程隊列)中,最后空閑線程會回收被刪除線程的資源。

空閑線程也提供了接口來運行用戶設置的鉤子函數(shù),在空閑線程運行時會調(diào)用該鉤子函數(shù),適合鉤入功耗管理、看門狗喂狗等工作。

主線程:

在我們上一篇博文中介紹 RT-Thread 啟動流程的時候,說到了系統(tǒng)啟動會創(chuàng)建main線程:

pYYBAGKugZKAMPHcAAAbMTA-wqk588.png


FreeRTOS只有空閑線程,并不會創(chuàng)建主線程,所以在FreeRTOS中,一般在main() 之前開啟調(diào)度,永遠不會執(zhí)行到main()。

結(jié)語

本文的主要目的是認識 RT-Thread 線程操作函數(shù),同時簡單的說明了一下 RT-Thread 線程管理的一些要點,說明了一下 RT-Thread 與 FreeRTOS 在線程操作某些地方的不同,此外還加了一些博主認為的細節(jié)的問題, 希望懂的小伙伴可以多多指教,不懂的小伙伴看完還是不明白的可以留言。講得不好的地方還希望能夠指出,我一定加以修正。

總的來說,本文內(nèi)容還是比較簡單的,小伙伴們可以開動起來,線程創(chuàng)建跑起來玩玩。優(yōu)先級,任務調(diào)度,線程死循環(huán)什么的情況都可以試試。更能加加深線程調(diào)度的理解。

下一篇 RT-Thread 記錄,我會講一講 RT-Thread 時鐘管理的內(nèi)容,系統(tǒng)時鐘,軟件定時器相關(guān)。

謝謝!

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4346

    瀏覽量

    63015
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    507

    瀏覽量

    19763
  • RT-Thread
    +關(guān)注

    關(guān)注

    31

    文章

    1306

    瀏覽量

    40426
收藏 人收藏

    評論

    相關(guān)推薦

    RT-Thread上CAN實踐

    開箱測試RT-Thread官方已完成了對英飛凌XMC7200EVK的移植,通過shell可以看到做好了uart3的console。本文將介紹如何進行RT-ThreadCan移植。接下來我們要完成CAN_FD的驅(qū)動移植,并正常啟動RT-T
    的頭像 發(fā)表于 11-13 01:03 ?1410次閱讀
    <b class='flag-5'>RT-Thread</b>上CAN實踐

    開源共生 商業(yè)共贏 | RT-Thread 2024開發(fā)者大會報名啟動!

    親愛的RT-Thread開發(fā)者我們很高興地宣布,一年一度的RDC(RT-ThreadDeveloperConference,RT-Thread開發(fā)者大會)正式啟動報名!2024RT-Threa
    的頭像 發(fā)表于 10-29 08:06 ?523次閱讀
    開源共生 商業(yè)共贏 | <b class='flag-5'>RT-Thread</b> 2024開發(fā)者大會報名啟動!

    2024 RT-Thread全球巡回 線下培訓火熱來襲!

    親愛的RT-Thread社區(qū)成員們:我們非常高興地宣布,2024年RT-Thread全球開發(fā)者線下培訓即將拉開帷幕!24年全球巡回培訓將覆蓋超10座城市及國家,為開發(fā)者提供一個深入學習RT-Thread嵌入式開發(fā)的絕佳機會。
    的頭像 發(fā)表于 08-07 08:35 ?1508次閱讀
    2024 <b class='flag-5'>RT-Thread</b>全球巡回 線下培訓火熱來襲!

    【好書推薦】RT-Thread設備驅(qū)動開發(fā)指南

    近年來國內(nèi)芯片產(chǎn)業(yè)和物聯(lián)網(wǎng)產(chǎn)業(yè)的快速崛起,行業(yè)發(fā)展迫切需要更多人才,尤其需要掌握嵌入式操作系統(tǒng)等底層技術(shù)的人才。隨著RT-Thread被更廣泛地應用于行業(yè)中,開發(fā)者對嵌入式驅(qū)動開發(fā)的需求越來越
    的頭像 發(fā)表于 08-01 08:35 ?744次閱讀
    【好書推薦】<b class='flag-5'>RT-Thread</b>設備驅(qū)動開發(fā)指南

    RT-Thread 新里程碑達成——GitHub Star 破萬!

    RT-Thread實時操作系統(tǒng)開源項目在GitHub上的star數(shù)量突破一萬!截止發(fā)文,RT-Thread作為實時操作系統(tǒng)在業(yè)界Star數(shù)量排名第一!倉庫地址:https://gith
    的頭像 發(fā)表于 07-04 08:35 ?524次閱讀
    <b class='flag-5'>RT-Thread</b> 新里程碑達成——GitHub Star 破萬!

    基于 RT-Thread專業(yè)版的EtherCAT主站方案

    特點。在RT-Thread實時操作系統(tǒng)上運行EtherCAT主站協(xié)議,大大提高了實時性,極大降低了循環(huán)同步抖動時間,可滿足各種對實時性要求苛刻的應用場景。以下是在瑞
    的頭像 發(fā)表于 06-19 08:35 ?1101次閱讀
    基于 <b class='flag-5'>RT-Thread</b>專業(yè)版的EtherCAT主站方案

    6月6日杭州站RT-Thread線下workshop,探索RT-Thread混合部署新模式!

    6月6日下午我們將在杭州舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺上實現(xiàn)同時運行RT-Thread和linux,本次workshop邀請到RT-Thread資深
    的頭像 發(fā)表于 05-28 08:35 ?493次閱讀
    6月6日杭州站<b class='flag-5'>RT-Thread</b>線下workshop,探索<b class='flag-5'>RT-Thread</b>混合部署新模式!

    2024 RT-Thread 全球技術(shù)大會演講議程發(fā)布!

    RT-ThreadGlobalTechConference(RT-ThreadGTC,RT-Thread全球技術(shù)大會)致力于圍繞RT-Thread基礎軟件技術(shù)發(fā)展、實踐創(chuàng)新、開發(fā)者能力
    的頭像 發(fā)表于 05-16 08:34 ?625次閱讀
    2024 <b class='flag-5'>RT-Thread</b> 全球技術(shù)大會演講議程發(fā)布!

    新書發(fā)布——《實時操作系統(tǒng)應用技術(shù):RT-Thread與ARM編程實踐》

    RT-Thread又一本新書《實時操作系統(tǒng)應用技術(shù)——基于RT-Thread與ARM的編程實踐》發(fā)布,標志著RT-Thread生態(tài)和實時操作
    的頭像 發(fā)表于 05-11 08:35 ?886次閱讀
    新書發(fā)布——《實時<b class='flag-5'>操作</b>系統(tǒng)應用技術(shù):<b class='flag-5'>RT-Thread</b>與ARM編程實踐》

    RT-Thread混合部署Workshop北京站來啦!

    4月25日,下午我們將在北京舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺上實現(xiàn)同時運行RT-Thread和linux,本次workshop邀請到RT-Thread資深
    的頭像 發(fā)表于 04-19 08:34 ?477次閱讀
    <b class='flag-5'>RT-Thread</b>混合部署Workshop北京站來啦!

    4月25日北京站RT-Thread線下workshop,探索RT-Thread混合部署新模式

    4月25日,下午我們將在北京舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺上實現(xiàn)同時運行RT-Thread和linux,本次workshop邀請到RT-Thread資深
    的頭像 發(fā)表于 04-16 08:35 ?472次閱讀
    4月25日北京站<b class='flag-5'>RT-Thread</b>線下workshop,探索<b class='flag-5'>RT-Thread</b>混合部署新模式

    4月10日深圳場RT-Thread線下workshop,探索RT-Thread混合部署新模式!

    4月10日我們將在深圳福田舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺上實現(xiàn)同時運行RT-Thread和linux,本次workshop邀請到RT-Thread資深嵌入式軟件工程師農(nóng)曉明老師為您講
    的頭像 發(fā)表于 03-27 11:36 ?893次閱讀
    4月10日深圳場<b class='flag-5'>RT-Thread</b>線下workshop,探索<b class='flag-5'>RT-Thread</b>混合部署新模式!

    4月10日深圳場RT-Thread線下workshop,探索RT-Thread混合部署新模式!

    4月10日我們將在深圳福田舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺上實現(xiàn)同時運行RT-Thread和linux,本次workshop邀請到RT-Thread資深
    的頭像 發(fā)表于 03-27 08:34 ?586次閱讀
    4月10日深圳場<b class='flag-5'>RT-Thread</b>線下workshop,探索<b class='flag-5'>RT-Thread</b>混合部署新模式!

    恩智浦半導體正式加入RT-Thread全球合作伙伴計劃!

    前不久,恩智浦半導體正式加入RT-Thread全球合作伙伴計劃,成為RT-Thread高級會員合作伙伴。同時,RT-Thread現(xiàn)已成為恩智浦注冊合作伙伴(RT-Thread| 簡介合
    的頭像 發(fā)表于 03-14 10:40 ?683次閱讀
    恩智浦半導體正式加入<b class='flag-5'>RT-Thread</b>全球合作伙伴計劃!

    RT-Thread設備驅(qū)動開發(fā)指南基礎篇—以先楫bsp的hwtimer設備為例

    RT-Thread設備驅(qū)動開發(fā)指南》書籍是RT-thread官方出品撰寫,系統(tǒng)講解RT-thread IO設備驅(qū)動開發(fā)方法,從方面進行講解。
    的頭像 發(fā)表于 02-20 16:01 ?1840次閱讀
    <b class='flag-5'>RT-Thread</b>設備驅(qū)動開發(fā)指南基礎篇—以先楫bsp的hwtimer設備為例