uC/OS中鎖調度器爲什麼比關中斷效率更高
1. 背景
今天看《μC/OS-III源碼分析筆記》的時候學習了通過使用鎖調度器代替關中斷,並使用中斷延遲提交,能夠大大節省關中斷的時間,提高運行效率。但是效率具體是如何提高的,書中的說明我沒有太看明白,於是我就把書中提到的函數的源代碼找出來分析了一下,希望能夠理解鎖調度器和關中斷兩者之間的區別。uC/OS完整源代碼可以從官網和我的Github上下載。
2. 優化原因
使用關中斷進入臨界區以後,系統不會響應中斷請求,如果臨界區裏需要做一些如I/O、與外設交互等需要進入較長時間的等待狀態的任務,此時CPU就處於忙等狀態,不能夠響應中斷去運行中斷處理程序,這就降低了系統的運行效率。
鎖調度器的方式可以保證當前運行的任務不會被其他任務搶佔,使任務進入了臨界區。
但是鎖住調度器之後還可以響應中斷,減少了關中斷的時間,使得CPU不會長時間處於忙等狀態,提高了系統的實時性和運行效率。
3. 關中斷和鎖調度器
3.1. 概念
-
中斷:中斷機制是處理器的重要基礎設施,用來應對各種事件的響應和處理。當外設或者處理器自身有事件發生時,處理器會暫停執行當前的代碼,並轉向處理這些中斷事務。中斷可分爲外部中斷、內部中斷和軟件中斷1。
-
搶佔:通過調度器實現,搶佔的發生可能是因爲有更高優先級的任務進入就緒隊列(優先級搶佔機制)或該任務的時間片已結束(時間片輪轉機制)。搶佔可分爲用戶搶佔和內核搶佔。
-
關中斷:進入臨界段,禁止其他中斷操作,關中斷以後產生的中斷請求會被掛起,等待開中斷以後再響應。
-
開中斷:退出臨界段,允許中斷操作。
-
鎖調度器:鎖住調度器(Lock the scheduler),不允許其他任務搶佔當前任務。
-
開啓調度器:解鎖調度器(Unlock the scheduler),允許其他任務搶佔當前任務。
-
RTOS:實時操作系統(Real Time Operating System)。
-
ISR:中斷服務程序(Interrupt Service Routine)。在CPU保護中斷現場之後,RTOS進入,進行中斷預處理,記錄當前中斷嵌套深度,查找用戶登記的中斷服務程序,然後CPU開始執行中斷服務程序1。
3.2. 源代碼
3.2.1. 開/關中斷
這裏有兩種方式通過關中斷進入臨界段
- CPU_INT_DIS()
- CPU_CRITICAL_ENTER()
若CPU_CFG_INT_DIS_MEAS_EN
標記爲False
,兩個函數完全一致,後者只是將前者封裝了一下。
若CPU_CFG_INT_DIS_MEAS_EN
標記爲True
,CPU_CRITICAL_ENTER()會記錄關中斷的時間。
#define CPU_INT_DIS() do { CPU_IntDis(); } while (0)
/* Disable interrupts. */
#define CPU_INT_EN() do { CPU_IntEn(); } while (0)
/* Enable interrupts.*/
#ifdef CPU_CFG_INT_DIS_MEAS_EN
/* Disable interrupts, ... */
/* & start interrupts disabled time measurement.*/
#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); \
CPU_IntDisMeasStart(); } while (0)
/* Stop & measure interrupts disabled time, */
/* ... & re-enable interrupts. */
#define CPU_CRITICAL_EXIT() do { CPU_IntDisMeasStop(); \
CPU_INT_EN(); } while (0)
/* -------------------------------------------- */
#else
#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); } while (0)
/* Disable interrupts.*/
#define CPU_CRITICAL_EXIT() do { CPU_INT_EN(); } while (0)
/* Re-enable interrupts.*/
#endif
3.2.2. 鎖調度器
- OS_CFG_ISR_POST_DEFERRED_EN:標記是否使用中斷延遲提交
// os_cfg.h
#define OS_CFG_ISR_POST_DEFERRED_EN 0u
/* Enable (1) or Disable (0) Deferred ISR posts*/
這裏有兩種方式進入臨界段
- 調用OS_CRITICAL_ENTER()鎖調度器。
- 先調用CPU_CRITICAL_ENTER()關中斷,再調用OS_CRITICAL_ENTER_CPU_EXIT()鎖調度器並開中斷。
-
若
OS_CFG_ISR_POST_DEFERRED_EN
標記爲False
,OS_CRITICAL_ENTER()實現的是關中斷,OS_CRITICAL_ENTER_CPU_EXIT()是一個空函數。 -
若
CPU_CFG_INT_DIS_MEAS_EN
標記爲True
,這裏的兩個函數都能實現鎖調度器的功能。
// os.h
#if (OS_CFG_ISR_POST_DEFERRED_EN == DEF_ENABLED)
/* Deferred ISR Posts */
/* Lock the scheduler*/
#define OS_CRITICAL_ENTER() \
do { \
CPU_CRITICAL_ENTER(); \
OSSchedLockNestingCtr++; \
if (OSSchedLockNestingCtr == 1u) { \
OS_SCHED_LOCK_TIME_MEAS_START(); \
} \
CPU_CRITICAL_EXIT(); \
} while (0)
/* Lock the scheduler but re-enable interrupts */
#define OS_CRITICAL_ENTER_CPU_EXIT() \
do { \
OSSchedLockNestingCtr++; \
\
if (OSSchedLockNestingCtr == 1u) { \
OS_SCHED_LOCK_TIME_MEAS_START(); \
} \
CPU_CRITICAL_EXIT(); \
} while (0)
/* Scheduling occurs only if an interrupt occurs*/
#define OS_CRITICAL_EXIT() \
do { \
CPU_CRITICAL_ENTER(); \
OSSchedLockNestingCtr--; \
if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) { \
OS_SCHED_LOCK_TIME_MEAS_STOP(); \
if (OSIntQNbrEntries > (OS_OBJ_QTY)0) { \
CPU_CRITICAL_EXIT(); \
OS_Sched0(); \
} else { \
CPU_CRITICAL_EXIT(); \
} \
} else { \
CPU_CRITICAL_EXIT(); \
} \
} while (0)
#define OS_CRITICAL_EXIT_NO_SCHED() \
do { \
CPU_CRITICAL_ENTER(); \
OSSchedLockNestingCtr--; \
if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) { \
OS_SCHED_LOCK_TIME_MEAS_STOP(); \
} \
CPU_CRITICAL_EXIT(); \
} while (0)
#else
/* Direct ISR Posts */
#define OS_CRITICAL_ENTER() CPU_CRITICAL_ENTER()
#define OS_CRITICAL_ENTER_CPU_EXIT()
#define OS_CRITICAL_EXIT() CPU_CRITICAL_EXIT()
#define OS_CRITICAL_EXIT_NO_SCHED() CPU_CRITICAL_EXIT()
#endif
4. 參考文獻
[1] 劉旭明. 嵌入式實時操作系統原理與最佳實踐. 機械工業出版社, 2014.
聯繫郵箱:[email protected]
Github:https://github.com/CurrenWong
歡迎轉載/Star/Fork,有問題歡迎通過郵箱交流。