中断机制详解
中断机制是现代计算机系统中不可或缺的一部分,它允许处理器在执行常规任务的同时,及时响应外部或内部的事件。本文将深入探讨中断机制的概念、类型、工作原理、实现方式及其在实际系统中的应用,并通过示例代码展示中断的具体实现。
中断机制概述
中断(Interrupt)是一种计算机系统用于处理异步事件的机制。通过中断,外部设备或内部事件可以打断处理器当前的执行任务,转而执行相应的中断服务程序(ISR),以快速响应和处理紧急事件。中断机制提高了系统的响应能力和资源利用率,是实现多任务和实时控制的基础。
中断与轮询的对比
在中断机制中,处理器只在需要时响应事件,这与轮询(Polling)机制形成鲜明对比。轮询要求处理器不断地检查设备状态,判断是否有事件需要处理,这在资源利用和响应时间上存在劣势。中断机制通过事件驱动的方式,避免了不必要的检查,提高了系统效率。
中断的类型
中断根据来源和触发方式的不同,可以分为多种类型。主要包括硬件中断和软件中断。
硬件中断
硬件中断由外部硬件设备发出,通常用于通知处理器某个事件的发生,如输入设备的操作、网络数据的到达、定时器的溢出等。硬件中断具有以下特点:
- 异步性:硬件中断可以在任意时间发生,与处理器当前的执行任务无关。
- 优先级:不同的硬件中断可以设定不同的优先级,决定中断的响应顺序。
- 快速响应:硬件中断能够迅速打断处理器的当前任务,确保及时处理重要事件。
常见的硬件中断源
- 键盘输入
- 网络接口
- 定时器
- 外部存储设备
软件中断
软件中断由程序通过特定指令发出,通常用于实现系统调用、异常处理或程序间通信。软件中断具有以下特点:
- 同步性:软件中断是由程序显式触发,与程序的执行流程密切相关。
- 可控性:程序可以根据需要发出中断,控制中断的时机和内容。
- 功能多样:软件中断常用于实现操作系统提供的服务,如文件操作、内存管理等。
常见的软件中断类型
- 系统调用(System Call)
- 异常处理(Exception Handling)
- 程序调试(Debugging)
中断的工作原理
理解中断机制的工作原理,是深入掌握中断机制的关键。中断的工作过程主要包括中断的触发、处理和恢复。
中断的触发与响应
当中断事件发生时,中断控制器(Interrupt Controller)会向处理器发送中断信号。处理器接收到中断信号后,执行以下步骤:
- 中断响应:处理器暂停当前指令的执行,保存当前的上下文信息(如程序计数器、寄存器等)。
- 中断识别:处理器根据中断向量表(Interrupt Vector Table)查找对应的中断服务例程(ISR)的地址。
- 执行中断服务例程:处理器跳转到ISR,执行中断处理逻辑。
- 恢复执行:ISR执行完毕后,处理器恢复之前保存的上下文信息,继续执行被中断的任务。
中断服务例程(ISR)
中断服务例程(Interrupt Service Routine,ISR)是专门用于处理中断事件的函数。ISR需要具备高效、快速的特点,以尽快完成中断处理,减少对系统其他任务的影响。
ISR的特点
- 简短高效:ISR应尽量简短,避免执行复杂的逻辑,以减少中断延迟。
- 重入性:ISR需要具备重入能力,以处理嵌套中断或同一中断的多次触发。
- 上下文保存:ISR需要保存和恢复被中断任务的上下文信息,确保系统的稳定性。
ISR专用堆栈
什么是 ISR 专用中断堆栈?
在嵌入式系统中,ISR(Interrupt Service Routine,中断服务程序)是用于处理硬件中断的特殊函数。当中断发生时,处理器会暂停当前正在执行的主程序,转而执行对应的 ISR。为了确保系统的稳定性和数据的完整性,ISR 有时会使用专用的中断堆栈,也就是为 ISR 独立分配的堆栈空间。
为什么 ISR 需要专用的中断堆栈?
-
堆栈空间隔离:
- 防止堆栈溢出: 如果主程序和 ISR 共用同一个堆栈,可能会因为堆栈空间不足而导致堆栈溢出,进而引发数据覆盖或系统崩溃。
- 数据安全性: 独立的堆栈可以防止 ISR 对主程序堆栈数据的意外修改,确保主程序的数据完整性。
-
提高系统的实时性和可靠性:
- 快速响应: 使用专用堆栈可以减少 ISR 进入和退出时的堆栈切换和保存操作,提高中断响应速度。
- 降低耦合性: 将 ISR 与主程序的堆栈分离,可以降低两者之间的耦合,便于系统的维护和升级。
-
支持嵌套中断:
- 堆栈深度管理: 在支持嵌套中断的系统中,ISR 专用堆栈可以更好地管理堆栈深度,防止因多级中断导致的堆栈溢出。
ISR 专用中断堆栈的工作原理
-
硬件支持:
- 处理器架构: 一些处理器(如 ARM Cortex-M 系列)内置了对多个堆栈指针的支持。例如,ARM Cortex-M 处理器有主堆栈指针(MSP)和进程堆栈指针(PSP)。中断发生时,处理器会自动切换到 MSP,从而实现 ISR 使用专用堆栈。
-
软件配置:
- 操作系统设置: 在某些嵌入式操作系统(如 RTOS)中,可以在系统初始化时为 ISR 分配专用的堆栈空间,所有的 ISR 共享这块堆栈。
- 编译器和链接器脚本: 通过配置链接器脚本,可以在内存中为 ISR 堆栈指定特定的地址范围。
-
中断处理流程:
- 进入中断: 当中断发生时,处理器会保存当前的程序计数器和状态寄存器,并切换到 ISR 专用堆栈。
- 执行 ISR: ISR 在专用堆栈上运行,不会影响主程序的堆栈内容。
- 退出中断: ISR 执行完毕后,处理器会从专用堆栈中恢复先前保存的状态,并返回主程序的堆栈继续执行。
示例
-
ARM Cortex-M 处理器中的堆栈指针:
- 主堆栈指针(MSP): 默认用于中断和异常处理。
- 进程堆栈指针(PSP): 通常用于主程序或线程的执行。
- 堆栈切换: 当中断发生时,处理器自动切换到 MSP,无需软件干预。
-
实时操作系统(RTOS):
- ISR 堆栈配置: 在 RTOS 中,通常会为 ISR 分配一个固定大小的堆栈空间,所有 ISR 共享。
- 任务堆栈独立: 每个任务有自己的堆栈,ISR 的堆栈与任务堆栈分离,防止相互干扰。
优点
- 提高系统稳定性: 防止堆栈溢出和数据覆盖,增强系统的可靠性。
- 简化中断处理: 独立的堆栈使得中断处理更为简单高效。
- 增强安全性: 避免 ISR 对主程序堆栈的不安全访问,保护主程序的数据。
需要注意的问题
- 堆栈大小配置: 需要合理设置 ISR 专用堆栈的大小,确保能够满足最深嵌套中断的堆栈需求。
- 系统资源消耗: 为 ISR 分配专用堆栈会占用额外的内存资源,需要在系统设计时平衡。
总结
ISR 专用中断堆栈是为中断服务程序提供的独立堆栈空间,旨在提高系统的可靠性和实时性。通过硬件支持或软件配置,ISR 可以在专用的堆栈上运行,避免对主程序堆栈的干扰。这在嵌入式系统和实时操作系统中是常见的设计,有助于构建稳定、高效的系统。
建议
- 了解目标处理器的架构: 查看处理器手册,了解其对堆栈指针和中断处理的支持。
- 合理配置堆栈大小: 根据应用需求和最坏情况下的中断嵌套深度,设置合适的 ISR 堆栈大小。
- 测试和验证: 在开发过程中,进行充分的测试,确保 ISR 堆栈不会溢出,系统运行稳定。
中断的实现方式
中断的实现涉及中断向量表、中断优先级和中断嵌套等机制。不同的系统架构和处理器设计可能会有不同的实现细节。
中断向量表
中断向量表(Interrupt Vector Table,IVT)是一个存储中断服务例程地址的表格。每个中断源对应一个唯一的中断向量,指向相应的ISR。
中断向量表的结构
在x86架构中,IVT通常位于内存的低地址部分,每个中断向量占用4字节,存储ISR的地址。具体结构如下:
中断向量号 | ISR地址(偏移量) |
---|---|
0 | 0x0000 |
1 | 0x0004 |
… | … |
示例代码:设置中断向量表
以下是一个简单的例子,展示如何设置中断向量表中的某个中断向量:
#define NUM_INTERRUPTS 256
typedef void (*ISR)(void);
// 定义中断向量表
ISR interrupt_vector_table[NUM_INTERRUPTS];
// 注册中断服务例程
void register_isr(int interrupt_number, ISR isr) {
if (interrupt_number >= 0 && interrupt_number < NUM_INTERRUPTS) {
interrupt_vector_table[interrupt_number] = isr;
}
}
// 示例ISR
void timer_isr(void) {
// 处理定时器中断
}
// 主函数
int main() {
// 注册定时器中断服务例程
register_isr(32, timer_isr);
while (1) {
// 主循环
}
return 0;
}
中断优先级与嵌套
在系统中可能会有多个中断源同时或几乎同时触发。为了合理地处理这些中断,系统需要设定中断的优先级,并支持中断的嵌套。
中断优先级
中断优先级决定了在多个中断同时发生时,处理器应该先响应哪个中断。优先级高的中断可以打断正在处理中优先级低的中断。
中断嵌套
中断嵌套(Interrupt Nesting)允许更高优先级的中断在低优先级的ISR执行期间被触发和处理。通过支持中断嵌套,可以提高系统的响应能力和实时性。
示例代码:处理中断优先级
以下示例展示了如何根据中断优先级处理不同的中断:
#include <stdio.h>
#include <stdlib.h>
#define NUM_INTERRUPTS 256
typedef void (*ISR)(void);
// 定义中断向量表
ISR interrupt_vector_table[NUM_INTERRUPTS];
int interrupt_priority[NUM_INTERRUPTS];
// 当前中断优先级
int current_priority = -1;
// 注册中断服务例程及优先级
void register_isr(int interrupt_number, ISR isr, int priority) {
if (interrupt_number >= 0 && interrupt_number < NUM_INTERRUPTS) {
interrupt_vector_table[interrupt_number] = isr;
interrupt_priority[interrupt_number] = priority;
}
}
// 模拟中断触发
void trigger_interrupt(int interrupt_number) {
if (interrupt_number < 0 || interrupt_number >= NUM_INTERRUPTS) return;
if (interrupt_vector_table[interrupt_number] == NULL) return;
// 检查优先级
if (interrupt_priority[interrupt_number] > current_priority) {
int saved_priority = current_priority;
current_priority = interrupt_priority[interrupt_number];
interrupt_vector_table[interrupt_number]();
current_priority = saved_priority;
}
}
// 示例ISR
void high_priority_isr(void) {
printf("处理中断:高优先级中断\n");
}
void low_priority_isr(void) {
printf("处理中断:低优先级中断\n");
}
// 主函数
int main() {
// 注册中断
register_isr(1, low_priority_isr, 1); // 低优先级
register_isr(2, high_priority_isr, 2); // 高优先级
// 触发中断
trigger_interrupt(1); // 低优先级中断
trigger_interrupt(2); // 高优先级中断
return 0;
}
输出:
处理中断:低优先级中断
处理中断:高优先级中断
中断的应用场景
中断机制广泛应用于各种系统中,尤其是在需要实时响应的场景中发挥着重要作用。
实时系统中的中断
实时系统要求在严格的时间约束内完成特定的任务。中断机制能够确保系统及时响应外部事件,满足实时性要求。例如:
- 工业控制系统:需要实时监控和控制生产线上的设备。
- 航空航天系统:需要实时处理传感器数据和执行控制指令。
- 医疗设备:需要实时监测患者生命体征并进行响应。
操作系统中的中断管理
操作系统通过中断机制实现多任务调度、设备驱动管理和异常处理等功能。中断在操作系统中的主要应用包括:
- 任务调度:定时器中断用于触发任务切换,实现多任务并发。
- 设备驱动:设备产生的中断用于通知操作系统完成数据传输或需要处理的事件。
- 异常处理:如页面错误、中断向量未定义等异常,通过软件中断进行处理。
中断的编程示例
通过具体的编程示例,可以更直观地理解中断机制的实现和应用。以下将分别展示嵌入式系统和操作系统内核中的中断处理示例。
嵌入式系统中的中断处理
在嵌入式系统中,中断处理通常涉及直接操作硬件寄存器,编写低级别的中断服务程序。以下示例基于ARM Cortex-M微控制器,展示如何配置和处理外部中断。
示例:GPIO中断处理
假设需要配置一个GPIO引脚为外部中断源,当引脚状态发生变化时,触发中断并执行ISR。
#include "stm32f4xx.h"
// 中断服务例程
void EXTI0_IRQHandler(void) {
if (EXTI->PR & (1 << 0)) {
// 检查中断挂起位
EXTI->PR |= (1 << 0); // 清除中断挂起位
// 处理中断事件
GPIOA->ODR ^= (1 << 5); // 切换LED状态
}
}
int main(void) {
// 使能GPIOA时钟
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
// 配置PA0为输入
GPIOA->MODER &= ~(0x3 << (0 * 2));
// 配置外部中断线0连接到PA0
SYSCFG->EXTICR[0] &= ~(0xF);
SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI0_PA;
// 配置中断触发方式为上升沿
EXTI->FTSR &= ~(1 << 0);
EXTI->RTSR |= (1 << 0);
// 使能EXTI0中断
EXTI->IMR |= (1 << 0);
// 设置中断优先级并使能NVIC中的EXTI0中断
NVIC_SetPriority(EXTI0_IRQn, 2);
NVIC_EnableIRQ(EXTI0_IRQn);
// 配置PA5为输出(连接LED)
GPIOA->MODER &= ~(0x3 << (5 * 2));
GPIOA->MODER |= (0x1 << (5 * 2));
while (1) {
// 主循环,等待中断触发
}
}
代码解析
-
GPIO配置:
- 使能GPIOA时钟。
- 配置PA0为输入,用作外部中断源。
- 配置PA5为输出,用于控制LED。
-
外部中断配置:
- 将外部中断线0连接到PA0。
- 配置中断触发方式为上升沿。
- 使能EXTI0中断,并设置中断优先级。
-
中断服务例程(ISR):
- 检查中断挂起位,确认中断源。
- 清除中断挂起位,避免重复触发。
- 切换LED状态,作为中断处理的示例操作。
操作系统内核中的中断处理
在操作系统内核中,中断处理涉及更复杂的任务,如任务调度、设备管理和异常处理。以下以简单的内核中断处理机制为例,展示如何处理中断并进行任务切换。
示例:简易内核中的中断处理
#include <stdint.h>
// 定义中断向量表
#define NUM_INTERRUPTS 256
typedef void (*ISR)(void);
ISR interrupt_vector_table[NUM_INTERRUPTS];
// 系统调用中断号
#define SYSCALL_INTERRUPT 0x80
// 当前任务控制块
typedef struct {
uint32_t *stack_pointer;
// 其他任务相关信息
} TCB;
TCB *current_task;
// 注册中断服务例程
void register_isr(int interrupt_number, ISR isr) {
if (interrupt_number >= 0 && interrupt_number < NUM_INTERRUPTS) {
interrupt_vector_table[interrupt_number] = isr;
}
}
// 系统调用服务例程
void syscall_handler(void) {
// 处理系统调用
// 例如,任务切换
schedule();
}
// 调度函数
void schedule(void) {
// 简单的轮询调度
current_task = get_next_task();
switch_task(current_task);
}
// 模拟获取下一个任务
TCB* get_next_task(void) {
// 返回下一个任务的控制块
// 这里只是示例,实际实现需维护任务队列
return current_task->next;
}
// 切换任务
void switch_task(TCB *task) {
// 保存当前任务的上下文
save_context(current_task);
// 加载新任务的上下文
load_context(task);
current_task = task;
}
// 模拟中断触发
void trigger_interrupt(int interrupt_number) {
if (interrupt_number < 0 || interrupt_number >= NUM_INTERRUPTS) return;
if (interrupt_vector_table[interrupt_number] != NULL) {
interrupt_vector_table[interrupt_number]();
}
}
int main(void) {
// 注册系统调用中断服务例程
register_isr(SYSCALL_INTERRUPT, syscall_handler);
// 初始化当前任务
// ...
while (1) {
// 主循环,执行任务
}
return 0;
}
代码解析
-
中断向量表:
- 定义一个包含256个中断向量的表,用于存储各中断号对应的ISR。
-
系统调用中断:
- 定义系统调用中断号为0x80。
- 注册系统调用ISR,负责处理系统调用请求,如任务调度。
-
任务调度:
- 简单的轮询调度策略,通过
get_next_task
获取下一个任务,并调用switch_task
切换任务。 switch_task
函数负责保存当前任务的上下文,并加载新任务的上下文。
- 简单的轮询调度策略,通过
-
中断触发:
trigger_interrupt
函数模拟中断的触发,通过调用对应的ISR来处理中断。
-
主函数:
- 注册系统调用ISR。
- 初始化当前任务。
- 进入主循环,执行任务。
中断机制的优缺点
中断机制在提升系统响应能力和资源利用效率方面具有显著优势,但也存在一些挑战和限制。
优点
-
高效响应:
- 中断允许系统在事件发生时立即响应,减少了事件处理的延迟。
-
资源节约:
- 通过中断机制,处理器无需频繁轮询设备状态,节省了处理器资源和功耗。
-
提高系统吞吐量:
- 中断机制使得系统能够同时处理多个异步事件,提高了系统的整体吞吐量。
-
支持多任务和实时性:
- 中断机制是实现多任务操作系统和实时系统的基础,确保了任务之间的有效切换和实时响应。
缺点
-
复杂性增加:
- 中断处理增加了系统设计和编程的复杂性,尤其是在中断嵌套和优先级管理方面。
-
调试困难:
- 中断的异步性使得调试变得更加困难,尤其是在中断频繁或嵌套的情况下。
-
中断开销:
- 每次中断触发都需要保存和恢复上下文,可能带来一定的性能开销。
-
优先级反转问题:
- 在多中断优先级的系统中,可能会出现低优先级中断阻塞高优先级中断的情况,影响系统的实时性。
中断机制的优化与挑战
为了充分发挥中断机制的优势,并克服其存在的缺点,系统设计中需要进行多方面的优化和考虑。
优化策略
-
中断屏蔽与优先级管理:
- 合理设置中断优先级,避免高优先级中断被低优先级中断阻塞。
- 使用中断屏蔽机制,临界区内禁用不必要的中断,确保关键操作的原子性。
-
中断服务例程的优化:
- 保持ISR简短高效,避免在ISR中执行耗时操作。
- 将复杂的处理逻辑转移到普通任务中,通过信号或消息机制进行通信。
-
使用中断向量表和动态注册:
- 通过中断向量表实现灵活的ISR注册和管理,支持动态添加和移除中断服务例程。
-
中断分级与分组:
- 对中断进行分级和分组,简化中断管理,提高系统的可维护性。
面临的挑战
-
中断嵌套与优先级反转:
- 在多中断系统中,嵌套中断可能导致优先级反转,需要采用优先级继承等机制解决。
-
实时性与中断开销的权衡:
- 在实时系统中,需要平衡中断处理的及时性与中断带来的上下文切换开销。
-
多核系统中的中断分配:
- 在多核处理器系统中,需要合理分配中断负载,避免单核过载或中断竞争。
-
硬件与软件协同设计:
- 需要硬件和软件共同设计中断机制,确保中断的高效处理和系统的稳定性。
总结
中断机制作为现代计算机系统的重要组成部分,极大地提升了系统的响应能力和资源利用效率。通过合理的中断类型分类、中断优先级管理和高效的中断服务例程设计,能够实现高效的事件驱动系统。然而,中断机制也带来了系统设计和调试的复杂性,需要在实际应用中进行细致的优化和管理。
附录:中断机制相关概念
中断控制器(Interrupt Controller)
中断控制器是管理和协调中断请求的硬件组件。它负责接收来自各中断源的中断信号,确定中断的优先级,并向处理器发送中断请求。常见的中断控制器包括可编程中断控制器(PIC)和高级可编程中断控制器(APIC)。
异步与同步中断
- 异步中断:由外部事件触发,与处理器当前的执行流程无关,如硬件中断。
- 同步中断:由指令执行过程中产生的异常触发,如软件中断和异常处理。
中断向量(Interrupt Vector)
中断向量是指向中断服务例程的地址,用于处理中断请求。中断向量的管理方式依赖于中断向量表,确保每个中断源有一个唯一的处理入口。
中断延迟(Interrupt Latency)
中断延迟是指中断发生到中断服务例程开始执行之间的时间。优化中断延迟是提高系统实时性的重要手段,通常通过减少中断处理的开销和优化中断响应机制实现。
中断共享与中断共用
在多设备系统中,多个设备可能共享同一个中断线。这种情况下,需要在ISR中通过查询设备状态或使用中断控制器的识别机制,确定具体的中断源,并进行相应处理。
参考文献
附加示例:软件中断的实现
除了硬件中断,软件中断也是中断机制的重要组成部分。以下示例展示了如何在x86架构下,通过软件中断实现系统调用。
; 示例:x86软件中断实现系统调用
section .data
message db 'Hello from ISR!', 0
section .text
global _start
_start:
; 调用系统调用
mov eax, 4 ; sys_write
mov ebx, 1 ; 文件描述符1(stdout)
mov ecx, message ; 要输出的字符串地址
mov edx, 16 ; 字符串长度
int 0x80 ; 触发软件中断
; 退出程序
mov eax, 1 ; sys_exit
xor ebx, ebx ; 返回码0
int 0x80 ; 触发软件中断
代码解析
-
数据段:
- 定义要输出的字符串
message
。
- 定义要输出的字符串
-
代码段:
_start
标签为程序入口点。- 设置系统调用参数:
eax
寄存器设置为4,表示sys_write
系统调用。ebx
设置为1,表示标准输出(stdout)。ecx
指向要输出的字符串地址。edx
设置为16,表示字符串长度。
- 使用
int 0x80
指令触发软件中断,执行系统调用。 - 设置
eax
为1,表示sys_exit
系统调用,退出程序。
编译与运行
使用NASM汇编器编译并运行上述代码:
nasm -f elf32 -o syscall.o syscall.asm
ld -m elf_i386 -s -o syscall syscall.o
./syscall
输出:
Hello from ISR!
总结
通过软件中断,可以实现程序与操作系统内核之间的交互,如文件操作、进程管理等。软件中断在系统调用机制中扮演着重要角色,确保用户态程序能够安全、受控地访问系统资源。
附录二:中断处理的安全性考虑
在设计和实现中断机制时,安全性是一个重要的考量因素。中断处理的不当可能导致系统的不稳定甚至崩溃,以下是一些关键的安全性考虑:
中断屏蔽与优先级管理
- 中断屏蔽:在执行关键操作时,适当屏蔽中断,防止中断打断关键代码的执行,避免数据不一致。
- 优先级管理:合理设置中断优先级,确保高优先级中断能够及时响应,同时避免优先级反转问题。
ISR的安全编程
- 避免使用全局变量:在ISR中尽量避免使用全局变量,减少数据竞争和共享资源的风险。
- 限制资源访问:在ISR中限制对共享资源的访问,必要时使用同步机制保护资源。
堆栈管理
- 堆栈空间:确保ISR使用的堆栈空间足够,避免因堆栈溢出导致系统崩溃。
- 堆栈保护:使用堆栈保护机制,防止恶意代码通过中断栈进行攻击。
异常处理
- 错误检测与恢复:在ISR中加入错误检测机制,确保中断处理过程中的异常能够被及时捕捉和处理。
- 回滚机制:在中断处理失败时,能够安全回滚到中断前的状态,避免系统进入不稳定状态。
示例:中断安全编程
以下示例展示了如何在中断处理中使用临界区,确保数据的一致性和安全性。
#include <stdint.h>
#include <stdbool.h>
volatile uint32_t shared_data = 0;
bool data_ready = false;
// 禁用中断
void disable_interrupts(void) {
__asm__("cli");
}
// 启用中断
void enable_interrupts(void) {
__asm__("sti");
}
// 中断服务例程
void data_isr(void) {
shared_data = read_hardware_data();
data_ready = true;
}
int main(void) {
// 注册中断服务例程
register_isr(DATA_INTERRUPT, data_isr, 1);
while (1) {
if (data_ready) {
disable_interrupts();
// 进入临界区,安全访问共享数据
process_data(shared_data);
data_ready = false;
enable_interrupts();
}
}
return 0;
}
代码解析
-
共享变量:
shared_data
和data_ready
用于在ISR和主程序之间共享数据。
-
中断服务例程(ISR):
- ISR从硬件读取数据,并设置
data_ready
标志。
- ISR从硬件读取数据,并设置
-
主程序:
- 检查
data_ready
标志,进入临界区,安全地访问shared_data
。 - 使用
disable_interrupts
和enable_interrupts
函数禁用和启用中断,确保临界区内的数据访问不被中断打断。
- 检查
安全性说明
通过禁用中断,确保在处理共享数据时不被其他中断打断,避免数据竞争和不一致问题。这种方法在需要高安全性的数据访问场景中尤为重要。