C 嵌入式系统设计模式 13:中断模式

本书的原著为:《Design Patterns for Embedded Systems in C ——An Embedded Software Engineering Toolkit 》,讲解的是嵌入式系统设计模式,是一本不可多得的好书。

本系列描述我对书中内容的理解。本文章描述访问硬件的设计模式之六:中断模式。

物理世界本质上是并发和异步的。

  • 并发 是指在同一时刻有多个活动(通常是任务或进程)正在发生或进行。在单线程环境中,并发通常是通过时间片轮转等机制模拟出来的,而在多线程或多核处理器环境中,多个任务可以同时进行。
    并发编程的目标是最大限度地利用计算资源,提高程序的响应性和吞吐量。为了实现并发,开发者通常会使用多线程、多进程、异步I/O等技术。
  • 异步操作 是指程序的某个部分可以在不等待其他部分完成的情况下继续执行。在异步编程中,任务的执行不会阻塞当前线程或进程,而是会立即返回并在后台继续执行。当任务完成时,通常会通过回调函数、事件、Promise等方式通知程序的其他部分。
    异步编程的主要好处是提高程序的响应性和性能,因为它允许程序在等待资源(如I/O操作)时继续执行其他任务。

在嵌入式系统和低级系统编程中,中断 是一种强大的机制,用于响应和处理外部事件或内部状态变化。中断处理程序是与特定中断类型相关联的代码段,当该类型的中断发生时,处理器会自动跳转到该代码段执行。由于中断可以打断正在执行的程序,因此它们提供了一种并发和异步处理事件的方式。这对于实时系统和嵌入式系统来说尤为重要,因为这些系统需要能够及时响应和处理外部事件,以确保系统的正确性和可靠性。此外,中断处理程序还可以用于实现诸如定时器、串行通信、输入/输出等操作,从而提高了系统的功能和性能。

摘要

中断模式在嵌入式系统和实时系统中非常常见,因为这些系统需要能够及时响应和处理外部事件。为了实现中断模式,开发人员需要利用处理器和编译器提供的中断服务例程(ISR)机制。ISR是与特定中断源相关联的代码段,当中断发生时,处理器会自动跳转到该代码段执行。在ISR中,开发人员可以编写用于处理中断事件的逻辑代码。处理完中断事件后,处理器会返回到被中断的程序继续执行。

问题

中断模式是一种强大且有效的机制,用于处理紧急和高频事件。与轮询模式相比,中断模式能够确保及时响应和处理这些事件,从而提高系统的实时性和可靠性。在中断模式中,当紧急事件发生时,处理器会立即暂停当前任务,跳转到与该事件相关联的中断服务例程(ISR)进行处理。处理完成后,处理器会返回到被中断的任务继续执行。这种机制确保了紧急事件能够得到优先处理,而不会被其他低优先级的任务所阻塞。

模式结构

模式结构图如下所示:
在这里插入图片描述

模式详情

中断处理

中断向量是一个指向中断服务例程(ISR)的指针或地址,当中断发生时,系统会查找对应的中断向量,并跳转到该向量指向的中断服务例程去执行。因此,通过修改中断向量表,我们可以控制哪个中断服务例程响应特定的中断。

中断处理install()deinstall() 函数提供了一种机制来动态地修改中断向量表。这使得我们可以在运行时安装或卸载中断服务例程,从而灵活地处理不同的中断事件。

每个 handleInterrupt_x() 函数都处理一个特定的中断,并以“从中断返回”(Return From Interrupt,RTI)语句结束。这条语句依赖于编译器和处理器。如前所述,至关重要的是中断服务例程不能有参数,这就是原因。否则当它们尝试返回时,将会从CPU堆栈中弹出错误的值。

中断向量表

InterruptVectorTable(中断向量表)实际上就是一个包含中断服务例程地址的数组。它位于处理器特定的内存位置。当中断号x发生时,CPU会暂停当前的处理,并间接调用该表中与第x个索引对应的地址。在RTI(从中断返回)指令执行后,CPU会恢复被暂停的任务。

效果

中断处理模式在嵌入式系统、操作系统和实时系统中非常常见,因为这些系统需要快速响应外部事件或内部状态变化。通过中断,系统可以在不等待当前任务完成的情况下,立即处理紧急事件,从而提高系统的响应性和实时性。

然而,由于中断会打断正常的程序流程,因此在使用中断时需要特别小心。如果中断服务例程执行时间过长,或者频繁触发中断,可能会导致系统性能下降或任务延迟。通常,当中断服务例程正在执行时,会禁用中断(不允许中断嵌套);这意味着中断服务例程必须执行得非常快,以确保不会错过其他中断。

由于中断服务例程(ISR)必须简短,因此如果在中断服务例程中调用其它系统服务时必须小心。例如,为了共享由中断发出的数据,中断服务例程可能需要将数据排入队列并快速返回;在将来的某个时刻,应用软件会在队列中发现这些数据。当数据的实际获取比其处理更为紧急时,这种机制非常有用。通过这种方式,可以将一个长时间的中断处理程序分解成两个部分:紧急部分,通过中断服务例程本身完成;处理部分,通过第二个函数完成,该函数定期检查数据或信号。

  • 如果中断服务例程处理时间过长,会延迟系统对其他中断的响应,可能导致实时任务错过截止时间或系统性能下降。这通常发生在中断服务例程执行了不必要的复杂操作,或者等待了某些不可用的资源。
  • 实现错误导致中断被禁用也是一个常见问题。当中断被禁用时,系统无法响应外部事件,可能导致重要任务被延迟或错过。这种错误通常是由于程序员对中断管理的不当理解或疏忽造成的。
  • 然而,共享资源上的竞争状态和死锁可能是最为棘手的问题。当多个中断服务例程或任务需要访问共享资源时,如果没有采取适当的同步措施,就可能出现竞争状态。这可能导致数据不一致、系统崩溃或其他不可预测的行为。死锁是竞争状态的一种极端情况,它发生在两个或多个中断服务例程或任务相互等待对方释放资源时,导致系统无法继续执行。

为了避免这些问题,需要采取一系列措施。首先,中断服务例程应该尽可能简短和高效,避免执行复杂操作或等待不可用资源。其次,需要确保中断管理代码的正确性,避免由于实现错误导致中断被禁用。最后,对共享资源的访问需要采取适当的同步措施,如使用锁、信号量或互斥量等机制来避免竞争状态和死锁的发生。

竞争状态(Race Condition)和死锁(Deadlock)都是并发编程中常见的问题:

  • 竞争状态 指的是当两个或多个进程在没有适当同步的情况下,访问共享的数据或资源,并且至少有一个进程在修改这些数据或资源时,最终的结果将取决于这些线程或进程的执行顺序。由于进程调度的不确定性,这可能导致不可预测和不可重复的结果。竞争状态通常是由于缺乏适当的同步机制(如互斥锁、信号量等)来确保对共享数据的互斥访问而引起的。
  • 死锁 则是指两个或多个进程在等待对方释放资源时陷入无限等待的状态,导致系统无法继续执行。这通常是由于每个进程都持有一个资源并请求另一个进程持有的资源,从而形成了一个循环等待的情况。如果没有外部干预,死锁将导致系统停滞不前,无法完成任何有用的工作。

如果中断服务例程和应用程序服务之间共享变量或数据结构(如队列),则访问这些资源构成了潜在竞争状态和死锁条件,因为你永远无法准确知道何时会执行中断服务例程。

下图展示了一种典型结构,其中中断服务例程与正常应用程序都访问同一共享资源,该共享资源是一个复杂数据结构。当应用程序正在访问共享资源时发生中断,就会出现竞争状态。想象一下,如果应用程序在读取数据的过程中(该读取操作不是原子操作)发生了中断,中断服务例程将会暂停应用程序的读取操作,转而执行中断服务例程,在此期间修改数据,然后返回到应用程序。这样,应用程序将会看到损坏的数据——部分是新的数据,部分是旧的数据。

在这里插入图片描述
对于这个问题,有多种解决方案,但它们都涉及到对共享资源的序列化访问。一种方法是在应用程序读取数据之前禁用中断,并在访问完成后重新启用中断。另一种方法是使用互斥信号量来保护数据,如下图所示。
在这里插入图片描述
在这张图中,共享资源 是受互斥信号量保护的;当调用 getData()setData() 函数时,会给资源 加锁 。当函数完成时,会给资源 解锁 。如果 中断服务例程 在尝试访问数据时等待信号量锁,就可能发生死锁。由于中断服务例程已经中断了拥有锁的 应用程序,假如中断服务程序一直等待信号量锁,则应用程序永远没有机会移除锁,因为它得不到运行,无法释放锁。当然,解决方案是中断服务例程不能等待锁。新数据可以被丢弃,或者可以创建两个共享资源,但规定中断服务例程或应用程序一次只能锁定其中一个资源。后一种解决方案有时被称为“双缓冲区”。双缓冲区方案比较复杂,如果你不希望这么做,那么唯一的选项是应用程序读取数据之前禁用中断,通常这是简单又常用的方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/707488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跨境电商与支付介绍

1、跨境电商定义和分类; 2、国际贸易清结算; 3、跨境支付; 1、跨境电商定义和分类 跨境电商业务简单说就是指不同国家地域的主体通过电子商务进行交易的一种业务模式。同传统的电商不同,交易双方属于不同的国家。因此&#xff0…

flask知识--01

flask介绍 # python 界的web框架: Django:大而全,使用率较高 :https://github.com/django/django -FastAPI:新项目选择使用它:https://github.com/tiangolo/fastapi -flask:公司一些…

Mysterious-GIF-攻防世界-MISC

题目简介: 下载得到gif文件,十六进制编辑器查看,发现末尾有50 4B 03 04文件头。提取后保存为zip文件。 解压该zip文件,得到temp.zip。十六进制编辑器查看temp.zip,会发现有多个文件头和文件尾。 用binwalk分离temp.zi…

如何在windows系统部署Lychee网站,并结合内网穿透打造个人云图床

文章目录 1.前言2. Lychee网站搭建2.1. Lychee下载和安装2.2 Lychee网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 图床作为图片集中存放的服务网站,可以看做是云存储的一部分,既可…

接口测试的测试要点

接口测试的测试要点,你知道都有哪些吗? 接口测试是软件测试中的重要组成部分,它的目的是评估接口的质量和可靠性,以保证系统的正常运行。在进行接口测试时,必须要考虑到以下几个方面: 测试用例的编写 测试…

ts的重载

官网示例 这里大概理解是 T 继承了Number|sting 加上&#xff1f;条件判断就是 T继承Number|sting 部分为true 没有继承部分为false&#xff0c; 就是输入string, 为true, 输入 null 则为false, type Exclude<T, U> T extends U ? never : T; // 相当于: type A …

CS_上线三层跨网段机器(完整过程还原)

以前讲过用cs_smb_beacon上线不出网机器&#xff0c;但是真实的网络拓扑肯定不止这么一层的网络&#xff01; 所以我就来搭建一个复杂一点的网络环境&#xff01;&#xff01; 当然了&#xff0c;这三台电脑之间都是不同的网段&#xff0c;&#xff08;但是同属于一个域环境&a…

golang学习7,glang的web的restful接口结构体传参

接口&#xff1a; //POST请求 返回json 接口传参json r.POST("/postJson", controller.PostUserInfo) 1.定义结构体 //定义结构体 type Search struct {Id intName string }2.结构体传参 //结构体传参 func PostUserInfo(c *gin.Context) {search : &Searc…

Qt6.8 GRPC功能使用(2)标准 Qt实现客户端

简介 基于之前的文章所说&#xff0c; Qt6.7之后才开始支持客户端、服务端、及双向流&#xff0c;恰好电脑需要重装&#xff0c;看到Qt6.8版本就直接安装了&#xff0c;内容也是使用Qt6.8的版本进行编译的 客户端实现步骤 1. 安装Qt6.8, 包含GRPC功能模块 Qt 6.8安装目录下包…

5G网络介绍

目录 一、网络部署模式 二、4/5G基站网元对标 三、4/5G系统架构对比 四、5G核心单元 五、边缘计算 六、轻量化&#xff08;UPF下沉&#xff09; 方案一&#xff1a;UPF下沉 方案二&#xff1a;UPF下沉 方案三&#xff1a;5GC下沉基础模式 方案四&#xff1a;…

05 动力云客之分页查询用户 + 查询用户详情 + 新增用户

1. 用户列表分页查询实现 核心 使用pageHelper实现分页 GetMapping(value "api/users")//分页的参数可以不传, 不传就默认设置为1public R userPage(RequestParam(value "current", required false) Integer current) {if (current null) {current …

docker下gitlab安装配置

一、安装及配置 1.gitlab镜像拉取 docker pull gitlab/gitlab-ce:latest2.运行gitlab镜像 docker run -d -p 443:443 -p 80:80 -p 222:22 --name gitlab --restart always --privilegedtrue -v /home/gitlab/config:/etc/gitlab -v /home/gitlab/logs:/var/log/gitlab -v …

table展示子级踩坑

##elemenui中table通过row中是否有children进行判断是否展示子集&#xff0c;通过设置tree-prop的属性进行设置&#xff0c;子级的children的名字可以根据自己的子级名字进行替换&#xff0c;当然同样可以对数据处理成含有chilren的子级list。 问题&#xff1a; 1.如果是根据后…

c++中使用lambda表达式的作用和用法

lambda表达式&#xff1a; 这是C11引入的一种新特性&#xff0c;它可以让您在需要定义函数对象的地方&#xff0c;直接编写一个匿名的、可以捕获上下文变量的函数体&#xff0c;非常适合用作回调函数、临时计算或定义小型函数对象。 lambda表达式与普通函数类似&#xff0c;也有…

存内计算技术大幅提升机器学习算法的性能—挑战与解决方案探讨

一.存内计算技术大幅机器学习算法的性能 1.1背景 人工智能技术的迅速发展使人工智能芯片成为备受关注的关键组成部分。在人工智能的构建中&#xff0c;算力是三个支柱之一&#xff0c;包括数据、算法和算力。目前&#xff0c;人工智能芯片的发展主要集中在两个方向&#xff1…

云计算新宠:探索Apache Doris的云原生策略

文章目录 Apache Doris 特性极简架构高效自运维高并发场景支持MPP 执行引擎明细与聚合模型的统一便捷数据接入 Apache Doris 极速 1.0 时代极速列式内存布局向量化的计算框架Cache 亲和度虚函数调用SIMD 指令集 稳定多源 关于 Apache Doris 开源社区基于云原生向量数据库Milvus…

腾讯云服务器宝塔面板中Docker应用无法访问

今天在用宝塔面板的时候用Docker一键部署Jenkins 发现部署好了端口也都开放了&#xff0c;防火墙也都开放了&#xff0c;安全组也都开放了。但是就是访问不了。 解决办法&#xff0c;在服务器终端执行下面指令 echo net.ipv4.ip_forward 1 >> /etc/sysctl.conf &…

vmware 中虚拟机Ubuntu磁盘不够,扩展磁盘,并分配

vmware 中虚拟机Ubuntu磁盘不够&#xff0c;扩展磁盘&#xff0c;并分配 Ubuntu虚拟机处于关机状态。虚拟机 -> 设置 ->硬盘 ->扩展 &#xff0c;可以直接多给点&#xff0c;这里只是做演示。 3.开启虚拟机&#xff0c;一般不会报错&#xff0c;我这里报错了&#…

Base 链官方点名 $AYB,继续飙涨指日可待?

近期 $AYB&#xff08;All Your Base Are Belong To Us&#xff09; 成为了 BASE 链上最火的 meme 项目&#xff0c;据悉 $AYB 在去年年底上线至今涨幅已经超过了 100 倍&#xff0c;其在被各大加密社区、KOL 追捧的同时&#xff0c;也被公认是继 Solana 上的 $BONK、Avalanche…

【Leetcode每日一题】二分查找 - 寻找旋转排序数组中的最小值(难度⭐⭐)(22)

1. 题目解析 Leetcode链接&#xff1a;153. 寻找旋转排序数组中的最小值 这个题目乍一看很长很复杂&#xff0c;又是旋转数组又是最小值的 但是仔细想想&#xff0c;结合题目给的示例&#xff0c;不难看出可以用二分的方法来解决 核心在于找到给定数组里面的最小值 2. 算法原…