91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

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

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

3天內不再提示

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

矜辰所致 ? 來源:矜辰所致 ? 作者:矜辰所致 ? 2022-06-20 00:31 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

前2課講完了RT-Thread開發(fā)環(huán)境,啟動流程,啟動以后當然是開始跑線程了,那么自然我們得學會如何創(chuàng)建線程以及線程的有關操作。

目錄

前言
一、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 設置調度器鉤子
二、RT-Thread線程創(chuàng)建示例
2.1 靜態(tài)創(chuàng)建線程示例
2.1 動態(tài)創(chuàng)建線程示例
三、RT-Thread線程管理簡析
3.1 線程調度的基本特點
3.2 線程控制塊
3.3 線程狀態(tài)
3.4 系統(tǒng)線程
結語

前言

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

但是后來又想了想:

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

好的,題外話說到這里,我們回到 RT-Thread 本身,上回我們已經把啟動流程講清楚了,
上文的最后講到:整個系統(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內核啟動流程 — 啟動文件和源碼分析

一、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ù)指定線程一次調度能夠運行的最大時間長度。
這個時間片運行結束時,調度器自動選擇下一個就緒態(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、線程句柄。線程句柄由用戶提供出來,并指向對應的線程控制塊內存地址,上面的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 體系結構中需要向 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ù)指定線程一次調度能夠運行的最大時間長度。
這個時間片運行結束時,調度器自動選擇下一個就緒態(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ù)組,本質就是開辟了一段連續(xù)的內存空間!這是用戶申請的,所以在編譯的時候就被確定分配好了,這段內存空間申請出來,通過rt_thread_init函數(shù),就分配給了這個線程使用。

如果知道了上面的話,但是還不能理解內存空間和線程有什么關系的時候,這個就得慢慢來……簡單來說就是,線程運行需要占用一段內存空間,這段內存空間每個線程的都不一樣,他們是用來線程運行的時候,函數(shù)調用線程切換保存現(xiàn)場用的。
反正先記住必須給每個線程單獨的一片內存空間,RTOS才能正常運行,所有的RTOS都是。
動態(tài)創(chuàng)建同樣的意思,只不過你看不到,由內核函數(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)建完成就開始運行參與調度了。

創(chuàng)建的線程狀態(tài)處于初始狀態(tài),并未進入就緒線程的調度隊列,我們可以在線程創(chuàng)建成功后調用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)這個問題, 其實從他們的定義就已經不同了,只不過rt_thread_t 和rt_thread 一眼看去還真可能傻傻分不清楚 = =!以前我剛用的時候也在這里迷糊了一會


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

rt_thread_t這個類型他是經過 typedef 重名命的:

pYYBAGKugY6AFcjLAAA33jozQiM609.png

所以回到開始的問題,搞清楚了rt_thread_startup 函數(shù)的參數(shù)是線程控制塊結構體指針, 再結合動態(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之前,我們需要定義兩個東西,一個結構體,一個數(shù)組:

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

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

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

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

句柄是什么?

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

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

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

(如果指針,指向指針的指針不明白,這是C語言基礎知識,可以查看相關資料,我有一篇博文也提到過一二: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);

調用該函數(shù)后,線程對象將會被移出線程隊列并且從內核對象管理器中刪除,線程占用的堆棧空間也會被釋放。實際上,用 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有一句話,同樣,線程本身不應調用這個接口脫離線程本身。這句話我理解就是不管動態(tài)刪除還是靜態(tài)刪除,不能在線程函數(shù)中自己把自己刪除。
這里也與FreeRTOS任務后不同,F(xiàn)reeRTOS可以直接在任務中調用函數(shù)刪除自己。

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

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

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 內核會自動把線程刪除?。?/p>

1.5 掛起和恢復線程

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

poYBAGKugY-AHofUAADH8yWiUeU475.png

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

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

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

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

1.6.1 獲得當前線程

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

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

1.6.2 讓出處理器資源

rt_err_t rt_thread_yield(void);

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

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

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

/*
參數(shù):tick/ms 	
線程睡眠的時間:sleep/delay 的傳入參數(shù) tick 以 1 個 OS Tick 為單位 ;
mdelay 的傳入參數(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ù)調用;
?RT_THREAD_CTRL_CLOSE:關閉一個線程,
等同于 rt_thread_delete() 或 rt_thread_detach() 函數(shù)調

用。
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ù)(不要和調度器鉤子函數(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 設置調度器鉤子

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

/*
參數(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);

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

注:請仔細編寫你的鉤子函數(shù),稍有不慎將很可能導致整個系統(tǒng)運行不正常(在這個鉤子函數(shù)中,基本上不允許調用系統(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線程管理簡析

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

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

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

3.1 線程調度的基本特點

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

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

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

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

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

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

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

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

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

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

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

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

pYYBAGKugZCAFA24AAA7uJ1Dcwk673.png

3.2 線程控制塊

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

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

我們來看看控制塊結構體(不是直接復制官網的哦?。?/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           		 /*多核相關支持,我們這里就一個M3內核*/    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					/*多核相關支持,我們這里就一個M3內核*/    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 內置線程定時器*/     /**< cleanup function when thread exit      線程退出清除函數(shù)     cleanup 函數(shù)指針指向的函數(shù),會在線程退出的時候,被idle 線程回調一次,     執(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() ,這是我們后期會介紹到的關于線程間通信的一些信號量,互斥量相關的函數(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 內核中的系統(tǒng)線程有空閑線程和主線程。

空閑線程 IDLE線程:

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

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

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

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

主線程:

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

pYYBAGKugZKAMPHcAAAbMTA-wqk588.png


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

結語

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

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

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

謝謝!

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

    關注

    3

    文章

    4417

    瀏覽量

    67494
  • 線程
    +關注

    關注

    0

    文章

    509

    瀏覽量

    20824
  • RT-Thread
    +關注

    關注

    32

    文章

    1611

    瀏覽量

    44810
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    恩智浦亮相RT-Thread 20周年開發(fā)者大會

    日前,“開源向實·生產力進化啟示錄”全球峰會暨RT-Thread 20周年開發(fā)者大會在上海成功舉辦,恩智浦作為RT-Thread的緊密合作伙伴,在活動中重磅亮相,展示雙方在共建RT-Thread OS開發(fā)生態(tài)方面的新成果、新方案
    的頭像 發(fā)表于 01-26 09:07 ?540次閱讀

    首搭RT-Thread程翧車控平臺| RT-Thread程翧 S32K344 快速原型開發(fā)平臺正式上市!| 產品動態(tài)

    在智能汽車邁向高集成與高安全的時代,VCU/ECU開發(fā)正面臨效率與可靠性的雙重考驗。依賴單一硬件或拼湊軟件方案的傳統(tǒng)模式,已成為制約創(chuàng)新的瓶頸。為此,RT-Thread帶來里程碑式的解決方案
    的頭像 發(fā)表于 10-31 11:53 ?985次閱讀
    首搭<b class='flag-5'>RT-Thread</b>程翧車控平臺| <b class='flag-5'>RT-Thread</b>程翧 S32K344 快速原型開發(fā)平臺正式上市!| 產品動態(tài)

    2025年RT-Thread開發(fā)者巡回培訓報名正式啟動!

    親愛的RT-Thread社區(qū)成員們:新程再啟,共赴熱愛!2025年RT-Thread開發(fā)者巡回培訓正式啟動報名!今年,我們選擇了西安、武漢、北京、杭州、深圳、上海、成都這7座城市,為大家?guī)?/div>
    的頭像 發(fā)表于 09-27 10:39 ?1959次閱讀
    2025年<b class='flag-5'>RT-Thread</b>開發(fā)者巡回培訓報名正式啟動!

    rt-thread studio 2.2.9如何使用最新的RT-Thread v5.2.0 released?

    rt-thread studio2.2.9如何使用最新的RT-Thread v5.2.0 released? 原先以為修改index_all.json,發(fā)現(xiàn)聯(lián)網的時候,會自動覆蓋 另lastet版本
    發(fā)表于 09-16 06:06

    在Ubuntu上開發(fā)基于先楫MCU的RT-Thread應用指南

    1、前言RT-ThreadEnv是RT-Thread推出的開發(fā)輔助工具,針對基于RT-Thread操作系統(tǒng)的項目工程,提供編譯構建環(huán)境、圖形化系統(tǒng)配置及軟件包管理功能。其內置的menu
    的頭像 發(fā)表于 08-29 12:22 ?1757次閱讀
    在Ubuntu上開發(fā)基于先楫MCU的<b class='flag-5'>RT-Thread</b>應用指南

    【好書推薦】RT-Thread第20本相關書籍!《嵌入式實時操作系統(tǒng)RT-Thread原理與應用》| 技術集結

    01內容簡介ContentSummary本書為讀者提供了一個全面、系統(tǒng)的RT-Thread學習指南,旨在幫助初學者及有經驗的開發(fā)者掌握RT-Thread實時操作系統(tǒng)和STM32嵌入式微控制器的核心
    的頭像 發(fā)表于 08-24 10:05 ?1005次閱讀
    【好書推薦】<b class='flag-5'>RT-Thread</b>第20本相關書籍!《嵌入式實時<b class='flag-5'>操作</b>系統(tǒng)<b class='flag-5'>RT-Thread</b>原理與應用》| 技術集結

    如何移植 RT-Thread Nano 并創(chuàng)建 2 個線程?

    基于 BSP 中的 GPIO_OutputInput 演示,展示了如何移植 RT-Thread Nano 并創(chuàng)建 2 個線程。
    發(fā)表于 08-19 07:45

    RT-Thread 遇上 Rust:安全內核 RusT-Thread 的誕生

    大家好,我們是中國科學技術大學操作系統(tǒng)原理與設計(H)課oooooS小組。這個項目是我們的課程大作業(yè):參考RT-Thread架構,使用Rust搭建一個原生的嵌入式操作系統(tǒng)內核。初識Rust是因為xk
    的頭像 發(fā)表于 08-02 11:03 ?3533次閱讀
    <b class='flag-5'>RT-Thread</b> 遇上 Rust:安全內核 RusT-<b class='flag-5'>Thread</b> 的誕生

    RT-Thread榮獲2025優(yōu)秀開源項目 | 新聞速遞

    6月底,RT-Thread睿賽德受邀參與由上海開源信息技術協(xié)會主辦的2025上海開源創(chuàng)新精英薈。上海市商委副主任張杰出席會議并致辭。RT-Thread嵌入式操作系統(tǒng)項目憑借其卓越的技術創(chuàng)新與開源生態(tài)
    的頭像 發(fā)表于 07-04 09:04 ?2635次閱讀
    <b class='flag-5'>RT-Thread</b>榮獲2025優(yōu)秀開源項目 | 新聞速遞

    深度剖析 RT-Thread 線程調度流程

    RT-Thread調度第一個線程的主要流程分如下:rtthread_startup:RTT的啟動函數(shù),主要負責板級驅動,調度器,系統(tǒng)線程初始化,啟動調度的工作
    的頭像 發(fā)表于 06-25 18:24 ?1763次閱讀
    深度剖析 <b class='flag-5'>RT-Thread</b> <b class='flag-5'>線程</b>調度流程

    揭秘RT-Thread上的AUTOSAR CP系統(tǒng)

    本文探討了RT-Thread與AUTOSARCP的融合,解決車載ECU開發(fā)中實時性、安全性與靈活性的平衡問題。通過分層安全內核(rt-safetyos/autoos)和工具鏈整合,兼容AUTOSAR
    的頭像 發(fā)表于 06-23 20:22 ?3215次閱讀
    揭秘<b class='flag-5'>RT-Thread</b>上的AUTOSAR CP系統(tǒng)

    玄鐵加入RT-Thread 高級會員合作伙伴 | 戰(zhàn)略新篇

    今天起,玄鐵XuanTie正式成為RT-Thread高級會員合作伙伴。此次合作標志著雙方將在嵌入式操作系統(tǒng)創(chuàng)新、RISC-V生態(tài)構建及行業(yè)應用落地等領域展開深度協(xié)同,加速推動開源技術的產業(yè)化進程
    的頭像 發(fā)表于 06-23 20:22 ?1104次閱讀
    玄鐵加入<b class='flag-5'>RT-Thread</b> 高級會員合作伙伴 | 戰(zhàn)略新篇

    2025 RT-Thread全球技術大會議程正式發(fā)布!

    。2024RT-Thread全球技術大會,由開源操作系統(tǒng)RT-Thread發(fā)起,并聯(lián)合國內外領先企業(yè)的重磅嘉賓,攜手國內外頂尖企業(yè)專家與超3萬名線上參與者,共議邊緣計算、嵌入式
    的頭像 發(fā)表于 05-27 19:28 ?1353次閱讀
    2025 <b class='flag-5'>RT-Thread</b>全球技術大會議程正式發(fā)布!

    【直播預告】《實時操作系統(tǒng)應用技術—基于RT-Thread與ARM的編程實踐》教學脈絡及資源簡介

    直播預告直播主題:《實時操作系統(tǒng)應用技術—基于RT-Thread與ARM的編程實踐》教學脈絡及資源簡介開放時間:2025年5月29日(周四)20:00主講老師:王宜懷課程類型:視頻直播觀看平臺
    的頭像 發(fā)表于 05-26 17:50 ?1252次閱讀
    【直播預告】《實時<b class='flag-5'>操作</b>系統(tǒng)應用技術—基于<b class='flag-5'>RT-Thread</b>與ARM的編程實踐》教學脈絡及資源簡介

    RT-Thread審核團招募: 深度參與開源RTOS社區(qū)治理與演進

    的開源實時操作系統(tǒng),正持續(xù)優(yōu)化社區(qū)協(xié)作流程,現(xiàn)面向全球開發(fā)者招募審核團(ReviewTeam)成員,共同維護代碼質量,推動RT-Thread生態(tài)繁榮發(fā)展!什么是RT
    的頭像 發(fā)表于 05-21 18:02 ?1250次閱讀
    <b class='flag-5'>RT-Thread</b>審核團招募: 深度參與開源RTOS社區(qū)治理與演進