使用中断禁用实现互斥
在任何操作系统中,许多进程同时运行,许多时候它们想要使用相同的共享变量或共享数据。每当一个进程正在使用某些共享资源时,我们说该进程处于临界区中。 临界区的主要规则非常简单但非常重要:任何两个进程不得同时处于同一个临界区。
如果两个进程同时进入临界区,数据将被破坏,产生错误的结果,系统可能会出现异常行为。因此,需要一种方法来确保一次只有一个进程进入。这种方法称为互斥。
有许多技术可以实现互斥。其中一种简单但古老的技术是使用中断禁用。本章将解释它的工作原理、为什么有效、存在的问题以及其适用场景。
什么是互斥?
在深入了解中断禁用之前,先理解互斥本身。每当一个进程处于临界区时,其他进程不得进入。这意味着一次只允许一个进程进入。 这可以保护共享数据免受意外更改。
示例:想象你和你的朋友都试图更新同一个银行余额。如果双方同时更新而没有任何规则,两个值可能会冲突,最终余额将错误。OS 通过互斥解决这个问题。
简单来说:互斥确保一次只有一个进程使用临界区。
具有优先级的互斥问题
有时进程具有不同的优先级。更高优先级的进程可能会抢占(停止)仍在临界区内的较低优先级进程。这很危险,因为较低优先级进程尚未完成对共享数据的更新。因此,OS 需要一个强有力的规则来防止这种干扰。这就是中断禁用可以提供简单解决方案的地方。
中断和进程切换
在理解解决方案之前,我们必须了解中断的作用。中断基本上是一个信号,告诉 CPU 停止当前进程并处理其他事情。
中断来自硬件、定时器、键盘、磁盘,甚至有时来自软件。每当发生中断时,CPU 就会从运行中的进程切换到另一个活动或另一个进程。
有两种主要事件会导致 CPU 切换进程:
- 内部事件 − 运行中的线程或进程执行了某些操作从而放弃 CPU。
- 外部事件 − 来自外部的中断,如定时器或硬件信号。
如果我们想在短时间内完全停止进程切换,则必须阻塞内部事件和外部事件。内部事件可以通过仔细编写代码来避免。但外部事件需要更强有力的手段。
停止外部事件的唯一方法是禁用中断
一旦禁用中断,CPU 就不会切换到另一个进程。它将继续运行当前进程,而不受任何干扰。

使用中断禁用实现互斥
获得互斥的最直接方法是让进程在进入临界区之前禁用中断。当中断被禁用时,OS 无法切换到另一个进程。因此,当前进程在处理共享变量时获得完全的安全性。
每当中断被禁用时,调度就会停止。没有其他进程能获得 CPU。这意味着只有当前进程能访问共享数据。
这种方法在单处理器系统中效果良好,因为一次只有一个 CPU 在运行。因为如果中断被禁用,CPU 将连续执行指令而不会中断,上下文切换不会发生。
因此,只要进程停留在临界区内,就没有人能强行介入。
为什么中断禁用能提供互斥
要理解为什么禁用中断能提供互斥,请考虑以下几点 −
- CPU 一次只运行一个进程。
- 进程切换只在明确定义的点发生。
- 这些切换点主要依赖于中断。
因此,如果中断被禁用 −
- 没有外部中断能到达。
- 没有定时器中断能到达。
- 没有硬件中断能到达。
- 因此,无法发生上下文切换。
如果无法发生上下文切换,那么就没有其他进程能进入临界区。 这为共享数据提供了完全保护,至少在单处理器系统中是这样。
互斥的要求
互斥需要满足一些条件 −
- 没有两个进程能同时进入。
- 临界区内的执行必须是原子的。
- 没有进程应该被不必要地延迟。
- 没有外部力量应该中断临界区。
当中断被禁用时,所有这些点都以简单的方式得到满足。因为 CPU 现在完全受当前进程控制,没有其他进程能运行。
中断禁用的缺点
尽管这种方法简单,但它也带来了许多问题。这就是为什么现代操作系统不太依赖这种方法。
系统时钟依赖中断
计算机的时钟通过从定时器设备接收定期中断来保持时间。如果中断被禁用,这些定时器信号就无法到达 CPU。这意味着系统时间可能会漂移或变得不准确。在某些系统中,这会造成大问题,因为许多任务依赖于正确的计时。
多处理器上的中断禁用无效
在单处理器上,禁用中断有效是因为只有一个 CPU。但在多处理器或多核系统中,即使一个 CPU 禁用了中断,其他 CPU 仍继续运行。因此,CPU 1 上的进程可能禁用了中断,但 CPU 2 上的另一个进程仍能访问共享数据。因此,无法保证互斥。
要在多处理器上使其生效,所有 CPU 必须同时禁用中断,这既慢又复杂。
长时间禁用中断会锁定系统
如果进程在临界区内停留太久,并且整个时间中断保持禁用,那么 −
- 键盘输入可能无法检测,
- 鼠标事件可能无法检测,
- 调度任务可能会延迟,
- 系统可能看起来冻结。
因此,禁用中断必须非常小心地使用,并且时间要短。
低优先级用户可能滥用它
如果任何简单的用户程序获得禁用中断的权限,整个 OS 都会变得不稳定。系统将无法切换进程并可能挂起。这就是为什么用户级程序不允许禁用中断。只有 OS 内核能做这项工作。
不适合实时系统
实时系统需要精确的计时、确切的调度,并且必须快速响应外部事件。如果中断被禁用,这种精确性就会丢失。因此,这种方法不适合实时操作系统。
内部事件 vs 外部事件
为了更好地理解中断禁用,让我们来看看控制 CPU 切换的两种事件类型。
内部事件
内部事件发生在运行中的线程内部。例如,
- 线程自愿放弃 CPU。
- 线程进入等待状态。
- 线程进行系统调用。
内部事件易于处理,因为进程本身在做出选择。
外部事件
外部事件来自 CPU 外部。例如,
- 定时器中断,
- 键盘中断,
- 磁盘中断,
- 鼠标中断,
- 网络中断。
要临时停止外部事件,必须禁用中断。这是唯一能保证没有意外事件干扰临界区的办法。
使用中断禁用的互斥步骤
以下是进程使用此技术的过程 −
步骤 1 − 进程想要进入临界区。
步骤 2 − 它禁用中断。
步骤 3 − 进入临界区并安全更新共享数据。
步骤 4 − 离开临界区。
步骤 5 − 重新启用中断。
只要中断被禁用,互斥就得到维持。此方法适用于单处理器系统、小型嵌入式系统、内核级关键操作、非常短的临界区(仅几条指令)。它不适合高负载多任务或基于多处理器的系统。
结论
使用中断禁用的互斥是操作系统中最简单和最早的技术之一。它通过停止所有中断确保只有一个进程进入临界区。这防止了 CPU 切换进程并保护共享变量。
但尽管这个想法很简单,它也有许多问题,如时序问题、多处理器问题和系统冻结。由于这些限制,现代操作系统很少直接使用此方法,除非是内核内部非常小且快速的操作。
不过,理解此方法很重要,因为它解释了早期 OS 设计的工作原理以及基本互斥思想的起源。今天锁、信号量和其他同步方法都源于这些早期思想。