本书的原著为:《Design Patterns for Embedded Systems in C ——An Embedded Software Engineering Toolkit 》,讲解的是嵌入式系统设计模式,是一本不可多得的好书。
本系列描述我对书中内容的理解。本文章描述嵌入式并发和资源管理模式之四:临界区模式
临界区模式
(Critical Region Pattern) 是一种 任务协作模式
。在软件设计中,任务协作模式是用于协调不同任务之间通讯和同步的策略。它旨在确保任务能够高效、有序地执行,并处理任务之间的依赖关系、优先级冲突和资源共享等问题。
临界区模式是任务协作中最简单的模式之一。其核心思想是在执行关键代码段时禁止任务切换,从而确保当前任务在执行这些敏感或不可中断的操作时不会被其他任务抢占。这种模式的使用场景通常涉及对共享资源的 独占访问
,或者需要确保任务在特定时间内 无中断地执行
以保证系统的稳定性和正确性。
在临界区模式中,当一个任务进入临界区时,它会关闭或禁用任务切换机制,以防止其他任务打断当前任务的执行。这样做可以消除与资源共享相关的并发问题,如数据竞争和条件竞争,因为在这个时间段内只有当前任务能够访问相关资源。一旦任务完成了临界区内的操作,它会重新启用任务切换,允许其他任务继续执行。
摘要
在抢占式多任务环境中,可能存在某些时间段,其中任务不能被中断或抢占。临界区模式通过禁用任务切换或甚至禁用中断来处理这些关键的时间间隔。这确保了当前任务能够不受干扰地执行。一旦退出临界区,任务必须重新启用任务切换(或中断),否则系统将无法正常运行。
问题
在两种情况下,任务不能被中断或抢占:
- 资源访问的互斥性:当任务正在访问共享资源,如全局变量或硬件设备时,如果这些资源不能同时被多个任务安全地访问,那么中断或抢占当前任务可能会导致数据竞争或资源状态的不一致。
- 操作的原子性和顺序性:有些操作必须在无中断的情况下完成,以确保其原子性(即操作要么完全执行,要么完全不执行)或特定的执行顺序。
效果
临界区模式通过禁止任务切换或中断来确保活动任务在执行关键代码段时不会受到其他任务的干扰。这使得任务能够在没有潜在干扰的情况下完成其工作,从而保证了系统的稳定性和可靠性。
需要小心的是,在退出临界区后必须重新启用任务切换或中断。
此外,因为要关闭中断或者禁用任务切换,所以临界区模式可能会影响其他任务的执行时间。出于这个原因,临界区的持续时间通常很短。
由于在临界区期间禁用了所有任务切换,因此不存在不受控制的优先级反转问题。
嵌套使用临界区可能会带来问题(通常是软件编写缺陷造成的),我们在实现 进入临界区函数
和 退出临界区函数
时要能支持嵌套。我来举一个不支持嵌套的例子来说明这种隐含缺陷。
CMSIS 也提供了使能中断和禁止中断的函数:
void __enable_irq(void); //使能中断
void __disable_irq(void); //禁止中断
查看反汇编,这两个函数分别对应着汇编代码:
CPSIE I ;使能中断
CPSID I ;禁止中断
这种禁止中断的方法是不支持嵌套使用的。比如一个这样的例子:
...
__disable_irq(); //进入临界区
...
//调用一个函数,在这个函数中也出现了开关中断操作(嵌套)
__disable_irq(); //再次进入临界区,这一步无错误
...
__enable_irq(); //退出临界区,开中断,这步提前打开了中断
//函数调用完毕
...
__enable_irq(); //期望在这里打开中断
...
注意看代码的第 7 行,这里退出临界区,开中断,从而提前打开了中断。根据代码逻辑,正确的打开中断应在代码的第 10 行。
RT-Thread
提供的使能全局中断或者禁止全局中断函数就具备嵌套使用的能力,具体例子可以参考我的博文 使能中断与禁止中断策略比较。
实现策略
这种模式通常通过使用调度器提供的服务来实现,例如OS_disable_task_switching()
和 OS_enable_task_switching()
(或类似的函数),或者通过引入汇编语言指令来在硬件级别禁用或启用中断处理。
无论使用哪种方法,都需要谨慎处理临界区的 进入
和 退出
,以确保不会意外地启用或禁用中断处理。此外,还需要注意临界区的长度和频率,以避免对系统性能产生过大的影响。如果临界区过长或频繁出现,可能会导致任务延迟、优先级反转或其他并发问题。
相关模式
这种模式仅在多个任务访问相同资源或服务,或者其他任务可能中断当前任务的时间关键处理时才适用。因此,它与 循环执行模式
(Cyclic Executive Pattern)并不适用,但经常与 静态优先级模式
(Static Priority Pattern)一起使用。
实例
见原书。
读后有收获,资助博主养娃 - 千金难买知识,但可以买好多奶粉 (〃‘▽’〃)