关调度与关中断

关调度与关中断

关中断与关调度是两种进入临界区的方式,它们有各自的使用环境。

最近在研究 ucos-III 的源代码时发现 ucos-III 中有对临界区的优化。以关调度来代替关中断的方式工作,系统可以在特定的情况下用关调度的方式来替代关中断,从而提高了整个系统的实时性。

首先,关闭了调度之后就不存在任务间的抢占问题,当前执行的代码只能被中断打断。不同于关中断的方式,关调度的过程中系统仍旧能够正常响应中断。

关调度确实有上述好处,但对使用环境的要求极为严格。凡是不能够在中断上下文中修改的内容,都可以通过关调度的方式来制造临界区。 容易理解,却很难应用。哪些是中断上下文中不能使用的 api?那些是中断上下文中不能使用的系统数据结构?只有理清楚这两点才能够正确的使用关调度来代替关中断,而这需要对实时操作系统有很深的了解。

什么样的行为会有什么样的过程将导致什么样的结果?这就是上述问题的一个简化。例如:在 ucos-III 中使用 OSTaskCreate 来创建任务时会发生怎样的过程?这样的过程会创建了哪些新的数据?又对系统中的哪些数据结构实例产生了影响?只有当我们能够掌控这其中的所有过程时,我们才能够发现用关调度替换关中断的时机。

关闭子中断

关中断以范围划分可以分为关闭总中断与子中断。在目标均能够正常完成的情况下,关闭子中断的方式能够增强系统的实时性。当然,仅仅在少数情况中可以使用关闭子中断的方式。使用不当则可能造成临界区保护不足的问题,这种问题极难定位,很难 debug

具体的示例如下:

  1. TCP/IP 协议栈中,协议栈不同层之间存在着共享的数据结构,必须要对这些数据结构进行保护。
    协议栈的数据结构仅由协议栈独有,用户通过调用协议栈提供的 api 接口直接或间接的操作这些数据结构。因此可以通过关闭与协议栈相关的子中断的方式来完成临界区保护。Net/3 中按照不同优先级提供相应的关中断的方式。这里的关中断以 “提升优先级” 的方式完成。如 splimp 函数通过将 CPU 优先级提升为网络设备驱动中使用的优先级来阻止任意网络设备中断的发生,从而实现临界区保护功能。

  2. linux早期内核中通过使用全局的 cli(),以关闭处理器上所有中断的方式来完成临界区保护。2.5 版本之后就以本地中断控制和自旋锁取缔了此种方式。事实上,关闭所有中断确实是一种同步问题的解决方案,但是这种方案的代价太大。结合局部性原理来说,你执行局部的代码,修改局部的数据结构,却要屏蔽所有中断,这未免也太不合理了吧!

总结

在本文中我讨论了关中断与关调度两种保护临界区的方式。就原理来看,关中断方式能够更彻底的保护临界区数据,却可能会造成系统实时性的降低。关调度的方式仅仅能在特定的环境中使用,却能够增强系统的实时性。具体应该使用哪种方式来进行临界区保护,需要根据实际情况来选择!

你可能感兴趣的:(嵌入式学习,Linux,龙瑜的,RTOS,视点)