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.
联系邮箱:curren_wong@163.com
Github:https://github.com/CurrenWong
欢迎转载/Star/Fork,有问题欢迎通过邮箱交流。