優先級翻轉問題

關於uC/OS-II中優先級翻轉問題

作者:秦紹華 陳滌   來源:山東大學    更新日期:2005-03-01

簡述:就uC/OS-II中的優先級翻轉問題與大家一同進行探討
原文發表於 單片機與嵌入式系統應用

1 uC/OS-II的運行機制

  在嵌入式系統的應用中,實時性是一個重要的指標,而優先級翻轉是影響系統實時性的重要問題。本文着重分析優先級翻轉問題的產生和影響,以及在uC/OS-II中的解決方案。

  uC/OS-II採用基於固定優先級的佔先式調度方式,是一個實時、多任務的操作系統。系統中的每個任務具有一個任務控制快OS_TCB,任務控制塊記錄任務執行的環境,包括任務的優先級,任務的堆棧指針,任務的相關事件控制塊指針等。內核將系統中處於就緒態的任務在就緒表(ready list)進行標註,通過就緒表中的兩個變量OSRdyGrp和OSRdyTbl[]可快速查找系統中就緒的任務。在uC/OS-II中每個任務有唯一的優先級,因此任務的優先級也是任務的唯一編號(ID),可以作爲任務的唯一標識。內核可用控制塊優先級表OSTCBPrioTbl[]由任務的優先級查到任務控制塊的地址。uC/OS-II主要就是利用任務控制快OS_TCB、就緒表(ready list)和控制塊優先級表OSTCBPrioTbl[]來進行任務調度的。任務調度程序OSSched()首先由就緒表(ready list)中找到當前系統中處於就緒態的優先級最高的任務,然後根據其優先級由控制塊優先級表OSTCBPrioTbl[]取得相應任務控制塊的地址,由 OS_TASK_SW()程序進行運行環境的切換。將當前運行環境切換成該任務的運行環境,則該任務由就緒態轉爲運行態。

  當這個任務運行完畢或因其它原因掛起時,任務調度程序OSSched()再次到就緒表(ready list)中尋找當前系統中處於就緒態中優先級最高的任務,轉而執行該任務,如此完成任務調度。若在任務運行時發生中斷,則轉向執行中斷程序,執行完畢後不是簡單的返回中斷調用處,而是由OSIntExit()程序進行任務調度,執行當前系統中優先級最高的就緒態任務。當系統中所有任務都執行完畢時,任務調度程序OSSched()就不斷執行優先級最低的空閒任務OSTaskIdle(),等待用戶程序的運行。

  2 uC/OS-II中的優先級翻轉問題

  在uC/OS-II中,多個任務按照優先級高低由內核調度執行,而且任務調度所花的時間是常數,與應用程序中建立的任務數無關。對於佔先式內核,任務的響應時間是確定的,而且是最優化的,佔先式內核保證最高優先級的任務最先執行。

  任務的響應時間=尋找最高優先級任務的時間+任務切換時間

  在uC/OS-II中尋找進入就緒態的最高優先級任務是通過查就緒表實現的,這減少了所需時間。

  y=OSUnMapTbl[OSRdyGrp];
  x=OSUnMapTbl [OSRdyTbl[y]];
  prio=(y<<3)+x;

  任務切換是通過調用匯編函數OS_TASK_SW()來實現的,主要完成兩個任務運行環境的保存和恢復。因此用戶可以通過安排任務的優先級,保證系統的實時性。當涉及到共享資源的互斥訪問時,多任務實時操作系統常常會出現優先級翻轉問題(priority inversion),不能保證高優先級任務的響應時間,影響系統的實時性,uC/OS-II中也存在同樣問題。所謂優先級翻轉問題(priority inversion)即當一個高優先級任務通過信號量機制訪問共享資源時,該信號量已被一低優先級任務佔有,而這個低優先級任務在訪問共享資源時可能又被其它一些中等優先級的任務搶先,因此造成高優先級任務被許多具有較低優先級的任務阻塞,實時性難以得到保證。

  例如:有優先級爲A、B和C的三個任務,優先級A>B>C,任務A,B處於掛起狀態,等待某一事件的發生,任務C正在運行,此時任務C開始使用某一共享資源S。在使用中,任務A等待的事件到來,任務A轉爲就緒態,因爲它比任務C優先級高,所以立即執行。當任務A要使用共享資源S時,由於其正在被任務 C使用,因此任務A被掛起,任務C開始運行。如果此時任務B等待的事件到來,則任務B轉爲就緒態。由於任務B的優先級比任務C高,因此任務B開始運行,直到其運行完畢,任務C纔開始運行。直到任務C釋放共享資源S後,任務A才得以執行。在這種情況下,優先級發生了翻轉,任務B先於任務A運行。這樣便不能保證高優先級任務的響應時間,解決優先級翻轉問題有優先級天花板(priority ceiling)和優先級繼承(priority inheritance)兩種辦法。

  優先級天花板是當任務申請某資源時,把該任務的優先級提升到可訪問這個資源的所有任務中的最高優先級,這個優先級稱爲該資源的優先級天花板。這種方法簡單易行,不必進行復雜的判斷,不管任務是否阻塞了高優先級任務的運行,只要任務訪問共享資源都會提升任務的優先級。在uC/OS-II中,可以通過OSTaskChangePrio()改變任務的優先級,但是改變任務的優先級是很花時間的。如果不發生優先級翻轉而提升了任務的優先級,釋放資源後又改回原優先級,則無形中浪費了許多CPU時間,也影響了系統的實時性。

  優先級繼承是當任務A申請共享資源S時,如果S正在被任務C使用,通過比較任務C與自身的優先級,如發現任務C的優先級小於自身的優先級,則將任務C的優先級提升到自身的優先級,任務C釋放資源S後,再恢復任務C的原優先級。這種方法只在佔有資源的低優先級任務阻塞了高優先級任務時才動態的改變任務的優先級,如果過程較複雜,則需要進行判斷。uC/OS-II不支持優先級繼承,而且其以任務的優先級作爲任務標識,每個優先級只能有一個任務,因此,不適宜在應用程序中使用優先級繼承。

  3 uC/OS-II中優先級翻轉問題的解決

  在uC/OS-II中,爲解決優先級翻轉影響任務實時性的問題,可以借鑑優先級繼承的方法對優先級天花板方法進行改進。對uC/OS-II的使用,共享資源任務的優先級不是全部提升,而是先判斷再決定是否提升。即當有任務A申請共享資源S時,首先判斷是否有別的的任務正在佔用資源S,若無,則任務A繼續執行,若有,假設爲任務B正在使用該資源,則判斷任務B的優先級是否低於任務A,若高於任務A,則任務A掛起,等待任務B釋放該資源,如果任務B的優先級低於任務A,則提升任務B的優先級到該資源的優先級天花板,當任務B釋放資源後,再恢復到原優先級。在uC/OS-II中,每個共享資源都可看作一個事件,每個事件都有相應的事件控制塊ECB。在ECB中包含一個等待本事件的等待任務列表,該列表包括OSEventTbl[]和OSEventGrp兩個域,通過對等待任務列表的判斷可以很容易的確定是否有多個任務在等待該資源,同時也可判斷任務的優先級與當前任務優先級的高低,從而決定是否需要用 OSTaskChangePio()來改變任務的優先級。

  這樣,僅在優先級有可能發生翻轉的情況下才改變任務的優先級,而且利用事件的等待任務列表進行判斷,比用OSTaskChangePio()來改變任務的優先級速度快,並佔用較少的CPU時間,有利於系統實時性的提高。

  總之,優先級翻轉問題是多任務實時操作系統普遍存在的問題,這個問題也存在於uC/OS-II中。通過在應用程序中進行簡單的判斷,在可能出現優先級翻轉的情況下動態的改變任務的優先級,可以有效地避免任務的優先級翻轉,保證高優先級任務的執行,提高了系統的實時性。

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