爲什麼要線程管理
在RTT中,線程是競爭系統運行資源的最小運行單位,而且RTT是一個支持多線程的操作系統,所以就會有各種線程要佔用CPU的資源。由於線程都是獨立的,每個線程都有單獨的堆棧空間、運行狀態…
所以,在線程進行切換的時候就很有必要保存每個線程的相關信息,即線程切換時的上下文環境(寄存器值、堆棧內容),這也是調度器的主要職責,當線程再次運行的時候,就可以從堆棧中找到上次運行的環境,從而恢復運行環境。
瞭解線程管理的必要性後還要知道RTT中的調度方式:
- 搶佔式調度
- 支持時間片輪轉調度
也就是不同優先級之間支持搶佔式調度,同一優先級間採用時間片輪轉機制。
線程的五種狀態
RTT中,線程有五種狀態:
- 初始態:線程創建之初就是初始態,此時還不能被調度
- 就緒態:此時線程在就緒列表中,可以被調度
- 運行態:此時線程正在執行,佔用CPU
- 掛起態:線程不在就緒列表,但也沒有被刪除,處於等待狀態
- 關閉態:此時線程運行結束,等待系統回收資源
總之RTT的線程就是在這五種狀態之間轉換,轉換規則如圖:
1.以就緒態爲中心,就緒態可以在掛起態和運行態之間切換;
2.運行態可以直接變爲掛起態,但掛起態必須經過就緒態才能轉換爲運行態;
3.只有運行態或者掛起態纔可以直接關閉;
4.線程只有在創建之初纔是初始態,通過rt_thread_startup()函數來進入就緒態。
線程掛起函數rt_thread_suspend()
可以用rt_thread_suspend()
函數來實現對指定線程的掛起,當然,rt_thread_delay()
函數也可以實現線程的掛起,rt_thread_delay()
使線程進入阻塞,效果和掛起一樣。這裏主要熟悉一下rt_thread_suspend()
函數,下面是RTT官方源代碼:
/**
* This function will suspend the specified thread.
*
* @param thread the thread to be suspended
*
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
*
* @note if suspend self thread, after this function call, the
* rt_schedule() must be invoked.
*/
rt_err_t rt_thread_suspend(rt_thread_t thread)
{
register rt_base_t temp;
/* 檢查線程的狀態 */
/* thread check */
RT_ASSERT(thread != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: %s\n", thread->name));
if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)
{
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",
thread->stat));
return -RT_ERROR;
}
/* 關閉中斷 */
/* disable interrupt */
temp = rt_hw_interrupt_disable();
/* 改變線程的狀態爲掛起態 */
/* change thread stat */
thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);
rt_schedule_remove_thread(thread);
/* 停止線程計時器 */
/* stop thread timer anyway */
rt_timer_stop(&(thread->thread_timer));
/* 打開中斷 */
/* enable interrupt */
rt_hw_interrupt_enable(temp);
RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));
return RT_EOK;
}
很簡單,使用時只需要把線程控制塊指針傳入形參即可,返回值會反饋掛起成功與否。
線程恢複函數rt_thread_resume()
既然有掛起,就會有恢復。線程恢複函數rt_thread_resume()
可以將線程從掛起態之間轉換爲就緒態(如果該線程優先級爲最高,之間轉到運行態),看一下RTT官方的源代碼:
/**
* This function will resume a thread and put it to system ready queue.
*
* @param thread the thread to be resumed
*
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
*/
rt_err_t rt_thread_resume(rt_thread_t thread)
{
register rt_base_t temp;
/* 檢查狀態 */
/* thread check */
RT_ASSERT(thread != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: %s\n", thread->name));
if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
{
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",
thread->stat));
return -RT_ERROR;
}
/* 關閉中斷 */
/* disable interrupt */
temp = rt_hw_interrupt_disable();
/* 將線程從掛起隊列移除 */
/* remove from suspend list */
rt_list_remove(&(thread->tlist));
rt_timer_stop(&thread->thread_timer);
/* 打開中斷 */
/* enable interrupt */
rt_hw_interrupt_enable(temp);
/* 將線程插入到就緒隊列 */
/* insert to schedule ready list */
rt_schedule_insert_thread(thread);
RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
return RT_EOK;
}
用法與掛起函數類似,只要傳入指定線程的線程控制塊即可,返回值會反饋恢復的結果。