RT-Thread學習記錄5 空閒線程及常用的鉤子函數

以下爲看視頻筆記..........

1.

空閒線程是一個比較特殊的系統線程,它具備最低的優先級。當系統中無其他就緒線程可運行時,調度器將調度到空閒線程。

空閒線程還負責一些系統資源回收以及將一-些處於關閉態的線程從線程調度列表中移除的動作

空閒線程在形式上是一個無線循環結構,且永遠不被掛起。

在RT-Thread實時操作系統中空閒線程向用戶提供了鉤子函數,空閒線程鉤子函數可以讓系統在空閒的時候執行一-些非緊急事務,例如系統運行指示燈閃爍,CPU 使用率統計等等。

像圖中的 tshell 和 tidle 稱爲系統線程,用戶自己創建的 led 稱爲用戶線程.

2. 空閒線程鉤子函數API

設置鉤子函數,把函數名傳遞給rt_thread_idle_sethook函數即可創建鉤子函數。

rt_err_t  rt_thread_idle_sethook(void (*hook)(void))

刪除鉤子函數

rt_err_t  rt_thread_idle_delhook(void(*hook)(void))

3. 空閒線程鉤子函數實例在代碼示例的 idlehook_sample.c 中,可以看到鉤子函數的具體操作。

實例:

/*
 * 程序清單:空閒任務鉤子例程
 *
 * 這個例程創建一個線程,通過延時進入空閒任務鉤子,用於打印進入空閒鉤子的次數
 */

#include <rtthread.h>
#include <rthw.h>

#define THREAD_PRIORITY      20
#define THREAD_STACK_SIZE    1024
#define THREAD_TIMESLICE     5

/* 指向線程控制塊的指針 */
static rt_thread_t tid = RT_NULL;

/* 空閒函數鉤子函數執行次數 */
volatile static int hook_times = 0;

/* 空閒任務鉤子函數 */
static void idle_hook()
{
    if (0 == (hook_times % 10000))
    {
        rt_kprintf("enter idle hook %d times.\n", hook_times);
    }

    rt_enter_critical();  //臨界區的保護,防止其他優先級高的線程打斷 hook_times++ 執行
    hook_times++;
    rt_exit_critical();    //解除臨界區的保護
}

/* 線程入口 */
static void thread_entry(void *parameter)
{
    int i = 5;
    while (i--)
    {
        rt_kprintf("enter thread1.\n");
        rt_enter_critical();
        hook_times = 0;
        rt_exit_critical();

        /* 休眠500ms */
        rt_kprintf("thread1 delay 50 OS Tick.\n", hook_times);  //一個系統滴答10ms
        rt_thread_mdelay(500);  //系統進入空閒線程運行,相應的鉤子函數就得到運行
    }
    rt_kprintf("delete idle hook.\n");
    
    /* 刪除空閒鉤子函數 */
    rt_thread_idle_delhook(idle_hook);  //刪除鉤子函數後,進入空閒線程時,設置的鉤子函數就不會運行了
    rt_kprintf("thread1 finish.\n");
}

int idle_hook_sample(void)
{
    /* 設置空閒線程鉤子 */
    rt_thread_idle_sethook(idle_hook);

    /* 創建線程 */
    tid = rt_thread_create("thread1",
                           thread_entry, RT_NULL, 
                           THREAD_STACK_SIZE, 
                           THREAD_PRIORITY, THREAD_TIMESLICE);
    if (tid != RT_NULL)
        rt_thread_startup(tid);

    return 0;
}

/* 導出到 msh 命令列表中 */
MSH_CMD_EXPORT(idle_hook_sample, idle hook sample);

用Keil 模擬的方式觀察程序運行結果,通過命令行的方式,在UART#1框內輸入idle_hook_sample 運行觀察。

我們通過rt_thread_idle_sethook()這個API爲系統空閒線程設置一個鉤子函數idle_hook,每當系統進入系統空閒線程時,

這個idle_hook()鉤子函數都得到有效的運行。當我們不需要鉤子函數運行時,可用rt_thread_idle_delhook()這個API刪除鉤子函數 。

4. 空閒線程鉤子函數使用注意事項

●空閒線程是一個線程狀態永遠爲就緒態的線程,所以鉤子函數中執行的相關代碼必須保證空閒線程在任何時刻都不會被掛起,例如rt_ thread_ delay()、rt_sem_take()[對信號量的操作API]等可能會導致線程掛起的阻塞類函數都不能在鉤子函數中使用,即鉤子函數不能被掛起。

●空閒線程可以設置多個鉤子函數,有一個鉤子函數列表的。

5.系統調度鉤子函數

系統的上下文切換是系統運行過程中最普遍的事件,有時用戶可能會想知道在某一-個時刻發生了什麼樣的線程切換,RT-Thread向用戶提供了一個系統調度鉤子函數,這個鉤子函數在系統進行任務切換時運行,通過這個鉤子函數,我們可以瞭解到系統任務調度時的一 些信息。在實例代碼中scheduler_hook.c 中。

rt_ scheduler_ sethook(void (*hook)(struct rt_ thread *from, struct rt_ thread *to))

/*
 * 程序清單:調度器鉤子
 * 在調度器鉤子中打印線程切換信息
 */

#include <rtthread.h>

#define THREAD_STACK_SIZE	1024
#define THREAD_PRIORITY	    20
#define THREAD_TIMESLICE    10

/* 針對每個線程的計數器 */
volatile rt_uint32_t count[2];

/* 線程1、2共用一個入口,但入口參數不同 */
static void thread_entry(void* parameter)
{
    rt_uint32_t value;

    value = (rt_uint32_t)parameter;
    while (1)
    {
        rt_kprintf("thread %d is running\n", value);
        rt_thread_mdelay(1000); //延時一段時間
    }
}

static rt_thread_t tid1 = RT_NULL;
static rt_thread_t tid2 = RT_NULL;

static void hook_of_scheduler(struct rt_thread* from, struct rt_thread* to)
{
    rt_kprintf("from: %s -->  to: %s \n", from->name , to->name);
}

int scheduler_hook(void)
{   
    /* 設置調度器鉤子 */
    rt_scheduler_sethook(hook_of_scheduler);
    
    /* 創建線程1 */
    tid1 = rt_thread_create("thread1", 
                            thread_entry, (void*)1, 
                            THREAD_STACK_SIZE, 
                            THREAD_PRIORITY, THREAD_TIMESLICE); 
    if (tid1 != RT_NULL) 
        rt_thread_startup(tid1);

    /* 創建線程2 */
    tid2 = rt_thread_create("thread2", 
                            thread_entry, (void*)2, 
                            THREAD_STACK_SIZE, 
                            THREAD_PRIORITY,THREAD_TIMESLICE - 5);
    if (tid2 != RT_NULL) 
        rt_thread_startup(tid2);
    return 0;
}

/* 導出到 msh 命令列表中 */
MSH_CMD_EXPORT(scheduler_hook, scheduler_hook sample);

 

 

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