1. 程式人生 > >RTthread學習筆記————第4章 執行緒管理

RTthread學習筆記————第4章 執行緒管理

  • 什麼是執行緒

執行緒,有時被稱為輕量級程序(Lightweight Process,LWP),是程式執行流的最小單元。一個標準的執行緒由執行緒ID,當前指令指標(PC),暫存器集合和堆疊組成。

RT-Thread 的執行緒排程器是搶佔式的,主要的工作就是從就緒執行緒列表中查詢最高優先順序任務,保證最高優先順序的執行緒能夠被執行,最高優先順序的任務一旦就緒,總能得到 CPU 的控制權。

  • 執行緒有哪些狀態

/* 執行緒控制塊 */
struct rt_thread
{
    /* rt 物件 */
    char name[RT_NAME_MAX]; /* 執行緒名稱 */
    rt_uint8_t type; /* 物件型別 */
    rt_uint8_t flags; /* 標誌位 */
    rt_list_t list; /* 物件列表 */
    rt_list_t tlist; /* 執行緒列表 */
    /* 棧指標與入口指標*/
    void *sp; /* 棧指標 */
    void *entry; /* 入口函式指標 */
    void *parameter; /* 引數 */
    void *stack_addr; /* 棧地址指標 */
    rt_uint32_t stack_size; /* 棧大小 */
    /* 錯誤程式碼 */
    rt_err_t error; /* 執行緒錯誤程式碼 */
    rt_uint8_t stat; /* 執行緒狀態 */
    /* 優先順序 */
    rt_uint8_t current_priority; /* 當前優先順序 */
    rt_uint8_t init_priority; /* 初始優先順序 */
    rt_uint32_t number_mask;
    ......
    rt_ubase_t init_tick; /* 執行緒初始化計數值 */
    rt_ubase_t remaining_tick; /* 執行緒剩餘計數值*/
    struct rt_timer thread_timer; /*內建執行緒定時器*/
    void (*cleanup)(struct rt_thread *tid); /* 執行緒退出清除函式 */
    rt_uint32_t user_data; /* 使用者資料 */
};
/*其中 init_priority 是執行緒建立時指定的執行緒優先順序,線上程執行過程當中是不會被改變的(除
非使用者執行執行緒控制函式進行手動調整執行緒優先順序)。cleanup 會線上程退出時,被空閒執行緒回撥
一次以執行使用者設定的清理現場等工作。最後的一個成員 user_data 可由使用者掛接一些資料資訊到
執行緒控制塊中,以提供類似執行緒私有資料的實現。*/

  1. 初始狀態:執行緒剛開始建立還沒開始執行時就處於初始狀態;在初始狀態下,執行緒不參與排程。此狀態在 RT-Thread                   中的巨集定義為 RT_THREAD_INIT。
  2. 就緒狀態:在就緒狀態下,執行緒按照優先順序排隊,等待被執行;一旦當前執行緒執行完畢讓出處理器,作業系統會馬上                   尋找最高優先順序的就緒態執行緒執行。此狀態在 RT-Thread 中的巨集定義為RT_THREAD_READY。
  3. 執行狀態:執行緒當前正在執行。在單核系統中,只有 rt_thread_self() 函式返回的執行緒處於執行狀態;在多核系統                      中,可能就不止這一個執行緒處於執行狀態。此狀態在 RT-Thread 中的巨集定義為RT_THREAD_RUNNING。
  4. 掛起狀態:也稱阻塞態。它可能因為資源不可用而掛起等待,或執行緒主動延時一段時間而掛起。在掛起狀態下,執行緒                   不參與排程。此狀態在 RT-Thread 中的巨集定義為 RT_THREAD_SUSPEND
  5. 關閉狀態:當執行緒執行結束時將處於關閉狀態。關閉狀態的執行緒不參與執行緒的排程。此狀態在 RT-Thread中的巨集定義                   為 RT_THREAD_CLOSE

  • 什麼是時間片

每個執行緒都有時間片這個引數,但時間片僅對優先順序相同的就緒態執行緒有效。系統對優先順序相同的就緒態執行緒採用時間片輪轉的排程方式進行排程時,時間片起到約束執行緒單次執行時長的作用,其單位是一個系統節拍(OS Tick),假設有 2 個優先順序相同的就緒態執行緒 A 與B,A 執行緒的時間片設定為 10,B 執行緒的時間片設定為 5,那麼當系統中不存在比 A 優先順序高的就緒態執行緒時,系統會在 A、B 執行緒間來回切換執行,並且每次對 A 執行緒執行 10 個節拍的時長,對B 執行緒執行 5 個節拍的時長。

  • 如何建立一個程序

建立一個動態執行緒: (動態)

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);

完全刪除執行緒:(動態)

rt_err_t rt_thread_delete(rt_thread_t thread);

 

初始化執行緒:(靜態)

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);



脫離執行緒:(靜態)

rt_err_t rt_thread_detach (rt_thread_t thread);

 啟動執行緒

rt_err_t rt_thread_startup(rt_thread_t thread);

獲得當前執行緒
 

rt_thread_t rt_thread_self(void);

使執行緒讓出處理器資源

rt_err_t rt_thread_yield(void);

/*呼叫該函式後,當前執行緒首先把自己從它所在的就緒優先順序執行緒佇列中刪除,然後把自己掛到
這個優先順序佇列連結串列的尾部,然後啟用排程器進行執行緒上下文切換(如果當前優先順序只有這一個線
程,則這個執行緒繼續執行,不進行上下文切換動作)。*/

使執行緒睡眠

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);

掛起和恢復執行緒

/*執行緒掛起使用下面的函式介面:*/
rt_err_t rt_thread_suspend (rt_thread_t thread);

/*執行緒恢復使用下面的函式介面:*/
rt_err_t rt_thread_resume (rt_thread_t thread);

控制執行緒

/*當需要對執行緒進行一些其他控制時,例如動態更改執行緒的優先順序,可以呼叫如下函式介面:*/
rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void* arg);

  • 為什麼會出現空閒執行緒

設定空閒鉤子

/*設定空閒鉤子函式*/
rt_err_t rt_thread_idle_sethook(void (*hook)(void));

/*注意:空閒執行緒是一個執行緒狀態永遠為就緒態的執行緒,因此設定的鉤子函式必須保證空閒執行緒在任
何時刻都不會處於掛起狀態,例如 rt_thread_delay() , rt_sem_take() 等可能會導致執行緒掛起的函
數都不能使用。*/

設定排程器鉤子

/*請仔細編寫你的鉤子函式,稍有不慎將很可能導致整個系統執行不正常(在這個鉤子函式中,
基本上不允許呼叫系統 API,更不應該導致當前執行的上下文掛起*/

void rt_scheduler_sethook(void (*hook)(struct rt_thread* from, struct
                                rt_thread* to));


/*鉤子函式 hook()的宣告如下:*/

void hook(struct rt_thread* from, struct rt_thread* to);

  • RTthread小結

  1. 普通執行緒不能陷入死迴圈操作,必須要有讓出 CPU 使用權的動作。
  2. 執行緒排程是基於優先順序搶佔的方式進行,優先順序相同的執行緒通過時間片輪詢執行。
  3. 動態執行緒的建立與刪除呼叫介面 rt_thread_create()與 rt_thread_delete();靜態執行緒的初始化與脫離呼叫介面rt_thread_init()與 rt_thread_detach()。要注意的是,由於能執行完畢的執行緒系統會自    動將其刪除,所以不推薦使用者使用刪除/脫離執行緒介面。

 

注:文章參考培訓教程