1. 程式人生 > >ucosii的任務排程原理(文章來自百度)

ucosii的任務排程原理(文章來自百度)

1. 任務切換由作業系統自動完成,切換工作是由軟體來完成主要功能,例如上下文的切換;還有部分工作由硬體來完成,例如通過中斷返回指令切換時硬體來完成程式暫存器等的恢復,所以它是架構相關部分,需要移植。而系統節拍只是觸發切換的一個事件,除此之外延時、中斷、任務阻塞等都可以直接導致任務的切換。
2. 一般通過一個延時來主動放棄對處理器資源的佔用,否則系統會在tick中斷時來自動切換(如果有更高優先順序任務),總之一切能夠導致任務切換的事件都可以打破對系統(CPU和其他資源)的獨佔。 任務的死迴圈並非處理器資源的死迴圈,它是一個執行線路的迴圈,系統可以允許多條線路分時共享系統資源並加以控制。 切換的本質是直接或間接呼叫切換函式,從而導致一個任務交出控制權。延時、互斥、同步、中斷等都是切換手段。
uCOSII工作核心原理是:近似地讓最高優先順序的就緒任務處於執行狀態。
作業系統將在下面情況中進行任務排程: 呼叫OS的API函式(使用者主動呼叫,如OSDelay(UINT tick), OSQPend(OSEVENT* pevent) ),中斷(系統佔用的時間片中斷OsTimeTick() 使用者使用的中斷).

排程演算法書上講得很清楚,我主要講一下整體思路。
(1) 在呼叫API函式時,有可能引起任務阻塞 如果系統API函式察覺到CurTask執行條件不滿足,需要進行任務切換就呼叫OSSched()排程函式,這個過程是系統自動完成的,使用者沒有參與。 OSSched()判斷是否切換,如果需要切換,則此函式呼叫OS_TASK_SW()。這個函式模擬一次中斷(在51裡沒有軟中斷,我用子程式呼叫模擬,效果相同),好象程式被中斷打斷了,其實是OS故意製造的假象,目的是為了任務切換。既然是中斷,那麼返回地址(即緊鄰OS_TASK_SW()的下一條彙編指令的PC地址)就被自動壓入堆疊,接著在中斷程式裡儲存CPU暫存器(PUSHALL)……。堆疊結構不是任意的,而是嚴格按照uCOSII規範處理。OS每次切換都會儲存和恢復全部現場資訊(POPALL),然後用RETI回到任務斷點繼續執行。這個斷點就是OSSched()函式裡的緊鄰OS_TASK_SW()的下一條彙編指令的PC地址。切換的整個過程就是,使用者任務程式呼叫系統API函式,API呼叫OSSched(),OSSched()呼叫軟中斷OS_TASK_SW()即OSCtxSw,返回地址(PC值)壓棧,進入OSCtxSw中斷處理子程式內部。反之,切換程式呼叫RETI返回緊鄰OS_TASK_SW()的下一條彙編指令的PC地址,進而返回OSSched()下一句,再返回API下一句,即使用者程式斷點。因此,如果任務從執行到就緒再到執行,它是從排程前的斷點處執行。
(2) 中斷會引發條件變化,在退出前必須進行任務排程。uCOSII要求中斷的堆疊結構符合規範,以便正確協調中斷退出和任務切換。前面已經說到任務切換實際是模擬一次中斷事件,而在真正的中斷裡省去了模擬(本身就是中斷嘛)。只要規定中斷堆疊結構和uCOSII模擬的堆疊結構一樣,就能保證在中斷裡進行正確的切換。任務切換髮生在中斷退出前,此時還沒有返回中斷斷點。仔細觀察中斷程式和切換程式最後兩句,它們是一模一樣的。POPALL+RETI。即要麼直接從中斷程式退出,返回斷點(切換後的高優先順序任務斷點);要麼先儲存現場到TCB,等到恢復現場時再從切換函式返回原來的中斷斷點(由於中斷和切換函式遵循共同的堆疊結構,所以退出操作相同,效果也相同)。使用者編寫的中斷子程式必須按照uCOSII規範書寫。任務排程發生在中斷退出前,是非常及時的,不會等到下一時間片才處理。OSIntCtxSw()函式對堆疊指標做了簡單調整,以保證所有掛起任務的棧結構看起來是一樣的。
(3)在uCOSII裡,任務必須寫成兩種形式之一(《uCOSII中文版》p99頁)(無限迴圈結構)。在有些RTOS開發環境裡沒有要求顯式呼叫OSTaskDel(),這是因為開發環境自動做了處理,實際原理都是一樣的。uCOSII的開發依賴於編譯器,目前沒有專用開發環境,所以出現這些不便之處是可以理解的。