Zephyr RTOS 兩種建立Thread的方式
Thread (執行緒)
在 Zephyr OS中,每個獨立的功能或任務可以放在不同的執行緒中執行,內部使用了輕量級的排程器,可以根據不同執行緒的優先級,以及執行緒本身的狀態(ready, running, pending 等),來決定哪一個執行緒能夠先被 CPU 執行,執行緒可以有以下幾個性質:
- 執行緒優先級(Priority):數值越小表示優先級越高(Preemptive scheduling 的情況下)。
 - 堆疊大小(Stack Size):每個執行緒必須設定自己的堆疊空間,Zephyr 會在執行緒切換時儲存或恢復執行緒的上下文。
 - 執行緒生命週期(Lifecycle):可以在編譯期就被預先配置好,或在執行期動態配置與建立。
 
Zephyr 建立執行緒的兩種常見方法
在編譯期間(Compile Time)建立執行緒
Zephyr 提供了一個巨集 K_THREAD_DEFINE() 用於在編譯期就宣告並建立執行緒。只要程式一開啟並初始化 RTOS 後,這些執行緒就會自動被建立並進入排程器的管理。
K_THREAD_DEFINE()
 |  | 
- name:此執行緒的識別名稱,同時會生成一個 k_tid_t 型態的變數。
 - stack_size:此執行緒的堆疊大小(以 byte 為單位)。
 - entry_fn:此執行緒進入點函式(thread function),開始執行時要跑哪個函式。
 - p1, p2, p3:最多可傳入三個參數給進入點函式使用(都為 void* 型態)。
 - prio:優先級(數值越小,優先級越高)。
 - options:執行緒選項,通常先給 0 表示沒有特別的額外設定。
 - delay:執行緒開始之前的延遲時間(ticks 或毫秒),若填 0 表示不延遲,立即就緒。
 
在執行期間(Run Time)建立執行緒
另一種是在程式運行期間建立執行緒,使用 API 函數k_thread_create() 建立執行緒。這種方法在有些情況下會更具彈性,例如依據狀態或條件,動態啟動或終止執行緒,以免靜態建立過多浪費資源。
k_thread_create()
 |  | 
- new_thread:指向使用者自行宣告的 struct k_thread 物件,用來儲存此執行緒的控制區塊。
 - stack:指向此執行緒對應的堆疊空間(需先以 
K_THREAD_STACK_DEFINE()靜態或動態配置)。 - stack_size:此堆疊的大小。
 - entry:執行緒執行的進入點函式。
 - p1, p2, p3:最多可傳入三個參數到執行緒函式。
 - prio:優先級。
 - options:執行緒選項,常用為 0。
 - delay:執行緒開始前是否要延遲。
 
範例
以下兩段程式碼,分別示範用 K_THREAD_DEFINE()(在編譯期間)或 k_thread_create()(在執行期間)建立兩個執行緒,分別執行 LED 漸亮漸暗(fade_led) 與 LED 閃爍(toggle_led) 的功能
github repo
以下是在Nucleo-F303K8的執行結果,左邊LED執行toggle,右邊執行fading

在編譯期間(Compile Time)動態建立執行緒範例
K_THREAD_DEFINE(fade_tid, 512, fade_led, NULL, NULL, NULL, 5, 0, 0);- 建立一個名為 fade_tid 的執行緒,堆疊大小 512 bytes,執行函式為 fade_led,優先級 5。
 - p1, p2, p3 都填 NULL,表示不需要傳遞參數。
 
K_THREAD_DEFINE(toggle_tid, 512, toggle_led, NULL, NULL, NULL, 5, 0, 0);- 同樣建立名為 toggle_tid 的執行緒,stack大小、優先級參數與上面一致,執行函式為 toggle_led。
 
這些執行緒在編譯的時候就已經被「靜態配置」了,所以當系統啟動並執行到 main() 時,它們也就由排程器自動啟動並不斷執行。
 |  | 
在執行期(Run Time)動態建立執行緒範例
若想要在程式執行的過程中(例如:由某個事件觸發)再建立執行緒,可以使用以下的做法:
1. 用 K_THREAD_STACK_DEFINE(my_stack_area, STACK_SIZE); 定義stack。
2. 定義一個 struct k_thread my_thread_data; 作為執行緒控制區塊(Thread Control Block, TCB)。
3. 呼叫 k_thread_create(),傳入上述的stack、控制區塊、進入點函式及其他參數來完成建立。
以下是一個範例,展示如何在 main() 函式中動態建立執行緒(此示例僅顯示與執行緒有關的部分,省略週邊初始化等重複程式碼):
 |  | 
比較
| 建立方式 | 特點 | 典型使用時機 | 
|---|---|---|
| Compile Time 建立 | K_THREAD_DEFINE() | 一開始已知需要的執行緒,以及系統資源充足時 | 
| Run Time 動態建立 | k_thread_create(),在程式執行時期再分配資源 | 不確定需要多少執行緒,或需要彈性創建/釋放 | 
- 如果確定在整個系統的生命週期中,執行緒數量固定,或是系統比較單純(例如一個簡單的多任務控制),用編譯期方式能減少程式碼的複雜度,也能讓程式一啟動就快速就緒。
 - 如果系統中會動態產生/取消某些任務(如:偵測到新裝置才開新任務等),就可以使用動態建立的方式,提高系統彈性。
 
總結
- 靜態(編譯期)建立執行緒:
- 使用 
K_THREAD_DEFINE() - 簡單、快速、程式架構清晰
 - 適用於固定且少數的長期執行緒
 
 - 使用 
 - 動態(執行期)建立執行緒:
- 使用 
k_thread_create() - 需要自行管理堆疊、控制區塊等
 - 適用於需要彈性創建和銷毀大量或不定數量執行緒的應用場景
 
 - 使用 
 
