讓線程既阻塞等待信號量又能執行週期任務的方法

在使用RTOS時,我們可能會遇到這樣一種場景:一個線程既要阻塞等待信號量或郵箱,又要執行週期性任務。本文介紹一種簡單的方法來實現該需求。

以信號量爲例,一般的RTOS提供的信號量請求具有以下3種請求方法:

①. 無限等待,即一直阻塞等待信號量。

②. 超時等待,即設定一個超時時間,如果超時時間內還沒有獲取到信號量,則不再繼續等待,線程繼續執行。

③. 嘗試等待,即嘗試獲取信號量,如果獲取不到則線程立即繼續執行。

我們可以使用超時等待的方法來實現線程既阻塞等待信號量,有能執行週期性任務,體的思路如下:將週期性任務的剩餘超時時間作爲要等待的信號量的超時時間,如果在超時時間內沒有獲取到信號量,就會退出信號量的等待,此時週期性任務的超時時間也剛好到了,可以執行一次週期性任務;如果在超時時間內獲取到了信號量,則先處理信號量然後重新計算週期性任務的剩餘超時時間,然後以該時間爲信號量的超時時間重新等待信號量。流程圖如下。

線程處理流程圖

使用這種方法,既不會錯過信號量消息,又可以定時執行週期任務,一舉兩得。事實上,LWIP中就使用了這種方法,以下代碼簡化了源碼,代碼註釋中提到的超時事件就是上文指的週期任務。 

static void tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
{
    u32_t sleeptime, res;

again:
    LWIP_ASSERT_CORE_LOCKED();

    /* 獲取超時事件的剩餘超時時間 */
    sleeptime = sys_timeouts_sleeptime();

    /* 如果超時事件的超時時間是永久,那麼永久等待信號量 */
    if (sleeptime == SYS_TIMEOUTS_SLEEPTIME_INFINITE)
    {
        UNLOCK_TCPIP_CORE();
        sys_arch_mbox_fetch(mbox, msg, 0);
        LOCK_TCPIP_CORE();
        return;
    }
    /* 如果超時事件的超時時間已到,執行一次超時處理 */
    else if (sleeptime == 0)
    {
        sys_check_timeouts(); 
        goto again;
    }

    UNLOCK_TCPIP_CORE();

    /* 以sleeptime作爲信號量的請求超時,請求信號量 */
    res = sys_arch_mbox_fetch(mbox, msg, sleeptime); 

    LOCK_TCPIP_CORE();

    /* 信號量等待超時,說明超時事件剛好超時,執行一次超時處理 */
    if (res == SYS_ARCH_TIMEOUT)
    {
        sys_check_timeouts();
        goto again;
    }
}

 

發佈了7 篇原創文章 · 獲贊 3 · 訪問量 1327
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章