22

我在这里看到了几个关于异常的问题,其中一些暗示将中断作为异常,但没有一个能明确连接。

  • 什么是中断?

  • 什么是例外?(请说明您知道的每种语言的例外情况,因为存在一些差异)

  • 什么时候异常是中断,反之亦然?

4

11 回答 11

21

您的处理器将有许多外部中断引脚。通常,这些引脚连接到硬件并用于指示某些外部事件何时发生。例如,如果您使用的是串行端口,UART 将提升连接到处理器上的中断引脚之一的引脚,以指示已接收到一个字节。

定时器、USB 控制器等其他外设也会根据一些外部事件产生中断。

当处理器在它的一个外部中断引脚上接收到信号时,它将立即跳转到内存中的某个指定位置并开始执行。执行的代码通常称为 ISR 或中断服务程序。除非您正在实施驱动程序或执行某种嵌入式软件,否则您不太可能遇到 ISR。

不幸的是,关于异常的问题的答案不太清楚 - 本页的其他答案中列出了 3 种不同的含义。

Ron Savage 的回答是指软件结构。这纯粹是一个应用程序级异常,其中一段代码能够指示可以被其他一些代码检测到的错误。这里根本没有硬件参与。

然后是任务所见的异常。这是一个操作系统级别的构造,用于在任务执行非法操作时终止任务 - 例如除以 0、非法访问内存等。

第三,存在硬件异常。就行为而言,它与中断相同,因为处理器将立即跳转到某个指定的内存位置并开始执行。异常与中断的不同之处在于异常是由处理器检测到的某些非法活动引起的。例如,处理器上的 MMU 会检测到非法内存访问并引发异常。这些硬件异常是操作系统执行其清理任务的初始触发器(如上段所述)。

于 2008-09-24T05:44:21.957 回答
11

中断由 CPU 外部的设备(定时器滴答、磁盘操作完成、网络数据包到达等)生成,并且与程序执行异步。异常与程序执行同步(例如被零除,访问无效地址)。

除非您的程序在没有操作系统的情况下执行(或者您正在开发操作系统),否则它永远不会看到原始异常/中断。它们被操作系统捕获并由它处理(中断),或者在被反射回用户程序之前转换为其他形式(例如 UNIX 上的信号,Windows 上的结构化异常处理(SEH)),在那里它有机会处理它。

于 2008-09-24T06:11:04.217 回答
9

中断是由硬件或特定 CPU 指令生成的 CPU 信号。这些会导致中断处理程序被执行。来自 I/O 硬件的 I/O 信号等事物会产生中断。

异常可以被认为是中断的软件版本,它只影响其进程。

我不确定确切的细节,但是可以通过中断来实现异常。

于 2008-09-24T04:25:02.007 回答
9

中断表明处理器内核外部的某些东西需要引起注意。它中断程序的正常流程,执行中断服务程序 (ISR),并通常返回到中断发生之前的位置。

这个基本主题有很多变化:中断可能由软件生成,另一个任务可能在 ISR 之后获得 CPU,等等。关键是中断可能随时发生,原因是代码/CPU没有控制

定义异常有点棘手,因为它可能具有三个层次的含义:

硬件异常

某些处理器(例如 PowerPC)定义异常以指示发生了某种异常情况:系统重置、无效地址、某些虚拟地址转换缓存未命中等...

这些异常也用于实现断点和系统调用。在这种情况下,它们的行为几乎就像中断。

操作系统异常

一些硬件异常将由操作系统处理。例如,您的程序访问无效内存。这将导致硬件异常。操作系统有一个针对该异常的处理程序,并且很可能操作系统会向您的应用程序(例如 SIGSEGV)发送一个信号,表示存在问题。

如果您的程序安装了信号处理程序,则信号处理程序将运行并有望处理这种情况。如果您没有信号处理程序,则可以终止或暂停程序。

我认为窗口的结构化异常处理程序 (SEH) 就是这种类型的异常。

软件异常

Some languages like Java, C++ and C# have the concept of software exceptions, where the language provides for the handling of unforeseen or unusual conditions related to the operation of the program. In this case, an exception is raised at some point in the code and some code higher up on the program execution stack would "catch" the exception and execute. This is what try/catch blocks do.

于 2008-09-24T12:23:07.723 回答
5

我将详细说明什么是中断,因为目前还没有人处理过一种关键类型的中断:计时器。

但首先,让我备份。当您收到中断时,您的中断处理程序(位于内核空间中)运行,通常禁用中断,查看任何待处理的业务(处理刚刚到达网络的数据包,处理击键等)然后(记住我们'此时仍在内核中)确定下一个应该运行的进程(可能是同一个进程,可能是不同的进程,取决于调度程序)然后运行它。

在任何给定时间,只有一个进程在处理器上运行。当您使用多任务操作系统时,它在它们之间切换的方式称为上下文切换 - 基本上处理器的寄存器被转储到内存中,流传递到新进程,当进程完成时,您将上下文切换到某些东西别的。

因此,假设我编写了一个简单的 C 程序来计算所有数字、斐波那契数列或其他东西而不会停止。甚至更好:除了在 while(1) 循环内旋转之外什么都不做。系统上的其他进程如何获得运行的机会?如果没有任何事情发生导致中断怎么办?

答案是您有一个不断中断的计时器设备。它是防止旋转过程破坏整个系统的原因。虽然我会注意到中断处理程序禁用中断,所以如果你做一些无限期阻塞的事情,你可以关闭整个系统。

于 2008-09-24T04:57:41.227 回答
5

例外

一个例外是处理器执行不在其正常路径上的代码。这是正常操作的“例外”,它本质上是通过代码和控制结构进行的线性移动。不同的语言支持各种类型的异常,通常用于处理程序运行期间的错误。

打断

中断是硬件级别的异常(通常)。中断是处理器中的一个物理信号,它告诉 CPU 存储其当前状态并跳转到中断(或异常)处理程序代码。一旦处理程序完成,原始状态就会恢复并且可以继续处理。

中断总是例外,即使它是有意的。中断可能表明:

  • 错误,例如内存访问冲突
  • 操作系统需要执行操作以支持正在运行的程序,例如软件中断或内存分页请求
  • 需要注意的硬件设备,例如收到的网络数据包或空的传输缓冲区

这些总是迫使处理器暂停其当前活动以处理引发的异常,只有在中断处理程序完成后才会恢复。

陷阱

在中断方面,常见的陷阱是竞争条件。例如,您可能有一个周期性地增加全局实时时钟的中断。在 32 位机器上,时钟可能是 64 位。

如果程序正在读取时钟,并获得第一个 32 位字,则中断发生,一旦中断处理程序退出,该进程将获得第二个 32 位字,数据将不连贯——这两个字可能不同步. 如果您尝试使用互斥锁或信号量来锁定进程中的变量,那么中断将挂起等待锁定并停止系统(死锁),除非处理程序和使用数据的进程都非常仔细地编写。写中断时很容易遇到麻烦。

可重入函数也是另一个问题。如果您在程序代码中执行 funcA,请使用一个也执行 funcA 的中断,您可能会因共享变量(静态或堆变量、类等)而导致意外后果。您通常希望在中断处理程序中执行尽可能少的代码,并经常让它设置一个标志,以便该进程稍后可以完成实际工作,而不必担心冲突。

在某些方面,这类似于为多处理器开发,这也是为什么内核编程仍然被许多人认为是黑魔法的原因之一。

-亚当

于 2008-09-24T05:19:27.353 回答
4

预计中断会定期发生(尽管有时它们不是定期发生的)。它们会中断cpu,因为刚刚发生了一些重要的事情,需要立即处理。

例外应该是规则的例外;这些是由软件抛出的,因为发生了意想不到的事情,这是您尝试对此做些什么的机会,或者至少可以优雅地崩溃。

于 2008-09-24T04:36:04.633 回答
2

当您谈论中断和异常时,您通常会接近硬件级代码,并且中断和异常通常部分由硬件实现,部分由软件实现。

中断是硬件中的事件(或在程序集中手动触发),它与可用于处理中断事件的处理程序向量相关联,例如 IO 完成、IO 错误(磁盘内存故障)、IO 事件(鼠标移动)例如)。当某些意外中断发生时,中断通常会引发异常。

异常是一种意料之外的行为,通常在使用硬件时,这些异常来自中断,并使用中断处理程序在软件中单独处理。我们看到的编程语言几乎总是将其伪装成某种控制结构。

于 2008-09-24T04:25:08.637 回答
2

通常,中断是某种硬件实现的陷阱。您为特定中断注册一个处理程序(除以 0,外设上可用的数据,定时器到期),当该事件发生时,所有处理系统范围的暂停,您快速处理中断,然后事情继续。这些通常在设备驱动程序或内核中实现。

异常是一种处理代码错误的软件实现方式。您为特定(或一般)异常设置处理程序。当发生异常时,语言运行时将开始展开堆栈,直到它到达该特定处理程序的处理程序。此时,您可以处理异常并继续,或退出您的程序。

于 2008-09-24T04:28:20.860 回答
2

中断基本上是硬件驱动的,例如您的打印机指示它“缺纸”或网卡指示它已失去连接。

异常只是程序中的错误条件,由 try / catch 块检测到。像:

Try
   {
   ... various code steps that "throw exceptions" on error ...
   }
catch (exception e)
   {
   print 'Crap! Something bad happened.' + e.toString()
   }

这是捕获代码块中发生的“任何错误”的便捷方法,因此您可以以类似的方式处理它们。

于 2008-09-24T04:28:41.623 回答
2

保持简单...

当你处理完一个中断后,你(通常)会回到你被打断之前正在做的事情。

处理异常涉及丢弃您当前正在处理的连续层,直到您冒泡到可以处理(捕获)异常的地步。

在处理中断时,您可能会决定抛出异常,但这并不意味着您必须将中断本身视为异常。异常不会“打断”(因为这意味着有可能回到你被打断之前正在做的事情);而是他们“中止”(某些子集)您当前的活动。

而且,正如已经多次提到的,中断通常由硬件或用户等外部实体触发(例如鼠标单击或 CTRL-C 之类的击键),而异常由软件检测到“问题”或“特殊情况”。

于 2008-09-24T07:01:28.637 回答