第6篇 zephyr kernel之多線程

目錄

摘要

1 zephyr線程的分類

1.1 協作線程

1.2 搶佔線程

2 線程的狀態

3 自動創建的線程

3.1 Main thread

3.2 Idle thread

3.3 其他自動創建的線程

4 線程創建

5 線程掛起與恢復

6 延時函數

6.1 s32_t k_msleep(s32_t ms)

6.2 k_usleep(s32_t us)

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,當我們程序中需要非常短的延時的時候,延時時間小於任務切換時間,那麼可以使用這個函數進行延時。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章