目錄
6.3 k_busy_wait(u32_t usec_to_wait)
本學筆記基於zephyr 工程版本 2.2.99,主機環境爲ubuntu18.04,開發平臺 nrf52840dk_nrf52840
摘要
多線程是每一個操作系統的基礎,一般情況下在實時操作系統中,任務(線程)的調度是基於優先級的。同時一個操作系統主要的功能就是對soc的資源和線程進行管理,線程管理包括線程的調度,線程間的通信,線程的生命週期,對soc資源管理主要包括cpu,ram等。
1 zephyr線程的分類
根據優先級不同,zephyr中主要包含兩類線程,分別是搶佔線程(preemptible thread)和協作線程( cooperative thread)。優先級是負數的被稱作協作線程,非負數的是搶佔式線程。在zephyr中優先級的數字越小優先級越高,比如優先級爲-2的線程高於優先級爲0的線程,而優先級爲0的線程高於優先級爲3的線程。
1.1 協作線程
優先級是負數的線程被稱作協作線程,優先級從 (-CONFIG_NUM_COOP_PRIORITIES
) to -1。一旦協作線程變爲當前運行的線程,它是不可以被其他線程(協作線程和搶佔線程)搶佔的,除非協作線程主動放棄cpu或者被中斷服務ISR搶佔。主動放棄cpu一般是等待資源(信號量,互斥鎖,郵箱等),執行睡眠(調用睡眠函數)和 k_yield()等操作。總之就是主動放棄cpu,其他線程才能得到執行。
1.2 搶佔線程
優先級爲非負數的線程被稱作搶佔式線程,優先級從0 to (CONFIG_NUM_PREEMPT_PRIORITIES
- 1)。搶佔線程可以被高優先級的搶佔線程和協作線程搶佔,當然也可以被ISR搶佔。這裏還有就是如果zephyr使能了時間片功能,那麼當有同優先級的線程存在,而且當前線程時間片耗盡,則同優先級的線程可以執行。
2 線程的狀態
3 自動創建的線程
3.1 Main thread
默認情況下,主線程使用搶佔線程的最高優先級(一般爲0,可配置)進行創建,並且他是一個"必須線程"(essential),必須線程就是這個線程不能終止,需要一直執行,否則系統引發錯誤。這個線程在mcu啓動時,zephyr內核初始化以後進行創建,入口就是我們所熟悉的main函數。
3.2 Idle thread
一般的操作系統都會包括一個空閒線程,空閒線程一般是最低優先級的線程。當所有其他線程放棄cpu以後,空閒線程得到執行,我們一般利用空閒線程進行cpu利用率統計或者低功耗處理。空閒線程也是一個essential線程,不能被結束。
3.3 其他自動創建的線程
當zephyr使能了工作隊列功能,系統啓動時會自動創建一個系統線程,用於處理工作隊列中的工作項。
4 線程創建
調用k_thread_create()
函數創建一個新的線程,線程有自己的stack區和線程控制塊(其他小系統也都類似,線程棧和控制是多任務的基礎),爲了確保stack區在適當的內存中,需要使用K_THREAD_STACK_DEFINE來定義stack區。線程被創建後,返回線程ID。
可以用如下代碼示例創建線程:
#define MY_STACK_SIZE 500
#define MY_PRIORITY 5
extern void my_entry_point(void *, void *, void *);
K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE);
struct k_thread my_thread_data;
k_tid_t my_tid = k_thread_create(&my_thread_data, my_stack_area,
K_THREAD_STACK_SIZEOF(my_stack_area),
my_entry_point,
NULL, NULL, NULL,
MY_PRIORITY, 0, K_NO_WAIT);
也可以在編譯時通過K_THREAD_DEFINE()聲明一個線程。與上面的效果相同:
#define MY_STACK_SIZE 500
#define MY_PRIORITY 5
extern void my_entry_point(void *, void *, void *);
K_THREAD_DEFINE(my_tid, MY_STACK_SIZE,
my_entry_point, NULL, NULL, NULL,
MY_PRIORITY, 0, K_NO_WAIT);
5 線程掛起與恢復
如果想要一個線程變爲掛起態,也就是暫停一個線程,那麼可以使用 k_thread_suspend()函數掛起線程,如果想恢復一個線程可以使用
k_thread_resume();
6 延時函數
6.1 s32_t k_msleep
(s32_t ms)
是當前運行的線程休眠一段時間,單位是ms,調用這個函數後,當前線程放棄cpu變爲waiting狀態,休眠期間不可以被調度器調度,當休眠到期後,線程變爲ready狀態,可以被調度器重新調度。
6.2 k_usleep
(s32_t us)
與k_msleep類似,單位是us,但是這個延時是不準確的,依賴於系統tick的精度。
6.3 k_busy_wait
(u32_t usec_to_wait)
與休眠不同,這個延時是忙等待,即不放棄cpu,延時單位是us,當我們程序中需要非常短的延時的時候,延時時間小於任務切換時間,那麼可以使用這個函數進行延時。