前言
本文对ucosiii中的临界区代码进行分析
正文
ucos源码中经常出现如下代码:
CPU_SR_ALLOC();
OS_CRITICAL_ENTER();
OS_CRITICAL_EXIT_NO_SCHED();
这是为了开启临界区,临界区内将不会出现任务切换。
假设没有临界区,如果有甲乙两个任务,甲要执行一段代码把abc三个值设置成123,如果甲把ab设置完12后出现任务切换,切换到任务乙,乙要把a设置成3,那么切换回来后,甲继续把c设置成3,这时甲认为abc的值为123,实际上却是323。
在OS_CRITICAL_ENTER()和OS_CRITICAL_EXIT_NO_SCHED()之间的代码称为临界区,临界区内将不会产生任务切换。
CPU_SR_ALLOC()的源码如下:
#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0
只是声明了一个变量cpu_sr
OS_CRITICAL_ENTER()的源码如下:
#define OS_CRITICAL_ENTER() \
do { \
CPU_CRITICAL_ENTER(); \
OSSchedLockNestingCtr++; \
if (OSSchedLockNestingCtr == 1u) { \
OS_SCHED_LOCK_TIME_MEAS_START(); \
} \
CPU_CRITICAL_EXIT(); \
} while (0)
CPU_CRITICAL_ENTER()是为了关闭系统中断,CPU_CRITICAL_EXIT()是为了开启系统中断,核心部分是OSSchedLockNestingCtr++,
OS_CRITICAL_EXIT_NO_SCHED()源码为:
#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
其中的核心为OSSchedLockNestingCtr--;
接下来对OSSchedLockNestingCtr变量进行分析,起到重要作用的两处是在OSSched (void)函数和OSIntExit (void)函数里,两个函数中都有如下代码:
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Scheduler still locked?
return;
}
可见两个函数都是判断到OSSchedLockNestingCtr不为0就不会执行。
两个函数的最后分别调用了:
#define OS_TASK_SW() NVIC_INT_CTRL = NVIC_PENDSVSET
#define OSIntCtxSw() NVIC_INT_CTRL = NVIC_PENDSVSET
这两个宏都是开启PendSV中断,进行任务切换,对PendSV的分析可以看【UCOSIII源码阅读笔记】第三篇——PendSV异常处理分析
所以开启临界区的最终目的是阻止开启PendSV中断,也就是阻止开启任务切换。
而对于应用层来说,ucos提供了两个函数用来实现OSSchedLockNestingCtr++和OSSchedLockNestingCtr--
分别是:
void OSSchedLock (OS_ERR *p_err) 任务切换加锁
void OSSchedUnlock (OS_ERR *p_err) 任务切换解锁
通过这两个函数对一段代码进行加锁保护,就可以防止出现访问冲突了。
769



被折叠的 条评论
为什么被折叠?



