OS_CORE.C(6)
生活随笔
收集整理的這篇文章主要介紹了
OS_CORE.C(6)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
先介紹一下優先級反轉的相關知識:
優先級翻轉是當一個高優先級任務通過信號量機制訪問共享資源時,該信號量已被一低優先級任務占有,因此造成高優先級任務被許多具有較低優先級任務阻塞,實時性難以得到保證。 例如:有優先級為A、B和C三個任務,優先級A>B>C,任務A,B處于掛起狀態,等待某一事件發生,任務C正在運行,此時任務C開始使用某一共享資源S。(A和C需要使用共享資源S,B不需要。)在使用中,任務A等待事件到來,任務A轉為就緒態,因為它比任務C優先級高,所以立即執行。當任務A要使用共享資源S時,由于其正在被任務C使用,因此任務A被掛起,任務C開始運行。如果此時任務B等待事件到來,則任務B轉為就緒態。由于任務B優先級比任務C高,因此任務B開始運行,直到其運行完畢,任務C才開始運行。直到任務C釋放共享資源S后,任務A才得以執行。在這種情況下,優先級發生了翻轉,任務B先于任務A運行。 這樣的話,會導致如果有很多任務處于A和C優先級之間,在一定的條件下,都會優于A先執行。這樣的話,A就被長時間阻塞。 解決優先級翻轉問題有優先級天花板(priority ceiling)和優先級繼承(priority inheritance)兩種辦法。 優先級天花板是當任務申請某資源時, 把該任務的優先級提升到可訪問這個資源的所有任務中的最高優先級, 這個優先級稱為該資源的優先級天花板。這種方法簡單易行, 不必進行復雜的判斷, 不管任務是否阻塞了高優先級任務的運行, 只要任務訪問共享資源都會提升任務的優先級。 優先級繼承是當任務A 申請共享資源S 時, 如果S正在被任務C 使用,通過比較任務C 與自身的優先級,如發現任務C 的優先級小于自身的優先級, 則將任務C的優先級提升到自身的優先級, 任務C 釋放資源S 后,再恢復任務C 的原優先級。這種方法只在占有資源的低優先級任務阻塞了高優先級任務時才動態的改變任務的優先級,如果過程較復雜, 則需要進行判斷。 notes:掛起狀態和就緒狀態是兩個不同的狀態。最主要的區別是看任務是否在內存中。掛起后,任務將被暫時調出內存;就緒時,是調入內存。 本篇介紹的是進入中斷和退出中斷函數:(注釋很詳細) /*$PAGE*/ /* ********************************************************************************************************* * ENTER ISR * 進入中斷(執行中斷) * Description: This function is used to notify uC/OS-II that you are about to service an interrupt * service routine (ISR). This allows uC/OS-II to keep track of interrupt nesting and thus * only perform rescheduling at the last nested ISR.該功能用來通知uc/os-II,正在進行一個中斷服務。該功能可以使uc/os-II追蹤中斷嵌套信息并且只能在最后嵌套中斷 * * Arguments : none * * Returns : none * * Notes : 1) This function should be called ith interrupts already disabled在任務級不能調用該函數 * 2) Your ISR can directly increment OSIntNesting without calling this function because * OSIntNesting has been declared 'global'.如果系統使用的處理器能夠執行自動的獨立執行讀取-修改-寫入的操作,那么就可以直接遞增265 * 中斷嵌套層數(OSIntNesting),這樣可以避免調用函數所帶來的額外開銷。在中斷服務子程序中266 * 給OSIntNesting加1是不會有問題的,因為給OSIntNesting加1時,中斷是關閉的 * 3) You MUST still call OSIntExit() even though you increment OSIntNesting directly.必須要有OSIntNesting()函數 * 4) You MUST invoke OSIntEnter() and OSIntExit() in pair. In other words, for every call * to OSIntEnter() at the beginning of the ISR you MUST have a call to OSIntExit() at the * end of the ISR. -- OSIntEnter()和OSIntExit()成對出現 * 5) You are allowed to nest interrupts up to 255 levels deep.中斷深度可達255 * 6) I removed the OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL() around the increment because * OSIntEnter() is always called with interrupts disabled. ********************************************************************************************************* */void OSIntEnter(void) {if (OSRunning == OS_TRUE) {if (OSIntNesting < 255u) { /*如果中斷層次<255*/OSIntNesting++; /* Increment ISR nesting level 增加中斷嵌套層次 */}} } /*$PAGE*/ /* ********************************************************************************************************* * EXIT ISR * 退出中斷(中斷完成) * Description: This function is used to notify uC/OS-II that you have completed serviving an ISR. When * the last nested ISR has completed, uC/OS-II will call the scheduler to determine whether * a new, high-priority task, is ready to run. * 該功能用來通知uc/os-II已完成中斷。當最后一個中斷嵌套完成時,uc/os-II將調用調度程序確定是否有個新的高優先級的任務準備運行 * Arguments : none * * Returns : none * * Notes : 1) You MUST invoke OSIntEnter() and OSIntExit() in pair. In other words, for every call * to OSIntEnter() at the beginning of the ISR you MUST have a call to OSIntExit() at the * end of the ISR.OSIntEnter()和OSIntExit()配套使用 * 2) Rescheduling is prevented when the scheduler is locked (see OS_SchedLock()) 給調度器上鎖用于禁止任務調度 (查看 OSSchedLock()函數) ********************************************************************************************************* */void OSIntExit(void) { #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register為CPU狀態寄存器分配存儲空間 */OS_CPU_SR cpu_sr = 0u; #endifif (OSRunning == OS_TRUE) { /*如果操作系統還在運行,關閉中斷*/OS_ENTER_CRITICAL();if (OSIntNesting > 0u) { /* Prevent OSIntNesting from wrapping 如果嵌套>0層,嵌套層減1 */OSIntNesting--;}if (OSIntNesting == 0u) { /* Reschedule only if all ISRs complete ...所有的中斷都完成了 */if (OSLockNesting == 0u) { /* ... and not locked.并且嵌套鎖也沒有了,即已經完全解鎖*/OS_SchedNew(); /*進行新一輪的調用*/OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];/*在任務優先級表中找到最高優先級任務*/if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy檢查具有最高優先級別的就緒任務的優先級是否是正在運行的任務的優先級。如果是,不用進行上下文切換*/ #if OS_TASK_PROFILE_EN > 0u /*如果不是*/OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task 進行上下文切換 */ #endifOSCtxSwCtr++; /* Keep track of the number of ctx switches上下文切換的次數(統計任務計數器) */OSIntCtxSw(); /* Perform interrupt level ctx switch 做中斷任務切換 */}}}OS_EXIT_CRITICAL(); /*打開中斷*/} }從上面的代碼也可以看出來:進入中斷函數很簡單,就是將中斷嵌套層數加1;退出中斷函數相對復雜,涉及到了上下文切換及相關的判斷。《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀
總結
以上是生活随笔為你收集整理的OS_CORE.C(6)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OS_CORE.C(5)
- 下一篇: OS_CORE.C(7)