chapter 6:信号和信号处理

发布时间 2023-11-12 16:23:37作者: 20211108俞振阳

学习笔记

6.0 摘要

这一章由华盛顿州立大学电气工程学院的K. C. Wang编写,涵盖了信号和信号处理。它提供了对信号和中断的统一处理,将信号视为Unix/Linux进程的中断。该章节解释了信号的来源、类型和处理步骤,包括进程结构中的信号处理程序及其在Interprocess Communication(IPC)中的作用。

6.1 信号和中断

  • 广义过程:

    • 将过程定义为一系列活动,包括人的例行事务、Unix/Linux过程和CPU执行。
  • 中断:

    • 发送到进程的事件,将其从正常活动中分流以进行中断处理。
    • 例如硬件信号、异常和其他进程的中断。
  • 中断的类别:

    • 个人中断:
      • 使个人从正常活动中分流的事件。
      • 根据来源进行分类:硬件、其他人、自我制造。
    • 进程中断(Unix/Linux中的信号):
      • 从硬件、其他进程或自我制造发送到进程的中断。
    • 硬件中断:
      • 发送到CPU的信号,来自硬件、其他处理器或自我制造。
    • 进程的陷阱错误:
      • 由进程错误引起的自我制造中断。

6.2 Unix/Linux 信号的示例

  1. Control_C键:

    • 生成SIGINT(2)信号,导致正在运行的进程终止。
  2. nohup命令:

    • 在后台运行进程,忽略SIGHUP(1)信号,在用户注销后继续存在。
  3. kill命令:

    • 使用SIGTERM(15)信号请求进程终止。
    • SIGKILL(9)确保终止,因为进程无法更改对此信号的响应。

6.3 Unix/Linux 中的信号处理

6.3.1 信号类型

  • Unix/Linux支持31种信号,每个都有唯一的符号名称和编号。

6.3.2 信号的来源

  • 来自硬件中断、异常和其他进程的信号。

6.3.3 进程 PROC 结构中的信号

  • 进程PROC有一个信号位向量、屏蔽位向量和信号处理程序。
  • 如果未被屏蔽,信号将生效。

6.3.4 信号处理程序

  • 进程PROC有一个信号处理程序数组。
  • 信号处理程序数组指定如何处理每个信号。

6.3.5 安装信号捕获器

  • 使用signal()系统调用更改信号处理程序。
  • signal()的局限性已由sigaction()取代,以获得更好的功能。

6.3.5.1 sigaction()系统调用

  • 支持比signal()更好的信号处理。
  • 允许阻塞其他信号,传递有关信号的其他信息,并适用于线程。

示例 6.6 - 使用sigaction()

  • 演示使用sigaction()系统调用进行信号处理的示例。

6.3.6 向进程发送信号

  • 使用kill()系统调用向其他进程发送信号。
  • 超级用户进程(uid=0)可以向任何进程发送信号。
  • 根据指定的pid提供信号的不同传递方式。

6.4 信号处理步骤

7. 进程检查和处理信号

  • 进程在内核模式下检查信号并处理未处理的信号。
  • 如果信号有用户安装的捕获函数,进程首先清除信号,获取捕获函数的地址,并对大多数与陷阱相关的信号重置捕获函数为默认。
  • 然后,它操纵返回路径,以便返回到以前进入内核模式的位置。
  • 这使进程在正常执行之前先执行捕获函数。然后它恢复正常执行。

8. 重置用户安装的信号捕获器

  • 用户安装的与陷阱相关的信号捕获函数旨在处理用户代码中的陷阱错误。
  • 为防止进程陷入无限循环,Unix内核通常在让进程执行捕获函数之前将处理程序重置为默认。
  • 这意味着用户安装的捕获函数只对信号的一次发生有效。为了捕获同一信号的另一个发生,必须重新安装捕获函数。
  • 对于用户安装的信号捕获器的处理不是一致的,因为在不同版本的Unix中会有所不同。

9. 信号和唤醒

  • Unix/Linux内核中有两种SLEEP进程:不可中断的深度睡眠进程和可中断的浅度睡眠进程。
  • 如果进程处于不可中断的SLEEP状态,到达的信号不会唤醒进程。
  • 如果它处于可中断的SLEEP状态,到达的信号将唤醒它。

6.5 信号和异常

10. 信号的正确使用

  • Unix信号最初设计用于以下目的:
    • 作为对进程异常的统一处理。
    • 允许进程通过预安装的信号捕获器在用户模式中处理程序错误。

6.6 信号作为IPC

11. 信号的滥用

  • 将信号用作进程间通信的机制在很多操作系统书籍中被归类。这个分类是值得质疑的,如果不是不合适的,原因如下:
    • 机制不可靠,可能导致信号丢失。
    • 存在竞态条件,可能导致信号丢失或进程终止。
    • 大多数信号有预定义的含义,不加选择地使用信号可能导致混淆。

示例 6.7 - 用于分段错误的捕获器

  • 演示如何使用信号捕获器和long jump来绕过引起分段错误的程序代码,使程序能够继续或优雅地终止。

6.7 Linux中的IPC

  • IPC指的是用于进程间通信的机制,在Linux中,IPC包括以下组件。

6.7.1 管道和FIFO

  • 管道和管道编程已在第3.10.1节中介绍。管道有读端和写端,用于连接管道写进程和读进程。

6.7.2 信号

  • 进程可以使用kill系统调用向其他进程发送信号,目标进程使用信号捕获器处理信号。使用信号作为IPC的一个主要弱点是,它们只能用作通知,不包含任何信息内容。

6.7.3 System V IPC

  • Linux支持System V IPC,包括共享内存、信号量和消息队列。

6.7.4 POSIX消息队列

  • POSIX标准(IEEE 1003.1-2001)定义了一种基于消息队列的IPC机制

,类似于System V IPC的消息队列但更通用和可移植。

6.7.5 线程同步机制

  • Linux不区分进程和线程。如果使用具有共享地址空间的clone()系统调用创建进程,它们可以通过使用互斥锁和条件变量在共享内存上进行通信。

6.7.6 套接字

  • 套接字是用于进程在网络上进行通信的IPC机制。套接字和网络编程将在第13章中介绍。

6.9 总结

本章涵盖了信号和信号处理。它提供了对信号和中断的统一处理,有助于正确理解信号。将信号视为对进程的中断,使进程从正常执行中转到信号处理。解释了信号的来源,包括来自硬件、异常和其他进程的信号。然后,使用示例说明了在Unix/Linux中信号的常见用法。详细解释了Unix/Linux中的信号处理,包括信号类型、信号向量位、信号掩码位、进程PROC结构中的信号处理程序和信号处理步骤。使用示例展示了如何在用户模式中安装信号捕获器来处理程序异常,如分段错误。还讨论了将信号作为进程间通信(IPC)机制的适用性。编程项目要求读者使用信号和管道实现进程之间的消息交换的IPC机制。

问题

1. 复习问题

(1). 以你自己的话定义“中断”。

回答: 中断是一种机制,用于暂时中止正在执行的程序,以便处理特定事件,然后返回执行原来的程序。

(2). 什么是硬件中断,进程中断?

回答: 硬件中断是由计算机硬件设备发送给CPU的信号,用于通知CPU发生了某个事件,需要处理。进程中断是由其他进程发送给目标进程的信号,用于通知目标进程发生了特定事件,需要处理。

(3). INT n 指令通常被称为软中断。INT n 和进程中断之间有什么区别?

回答: INT n 是通过执行软中断指令触发的,通常用于执行特定的系统调用。进程中断是由其他进程发送的信号,通知目标进程进行某种处理。

(4). 进程在处理信号之前,内核通常将信号处理程序重置为默认值。为什么需要这样做?

回答: 这是为了防止信号处理过程中出现问题,确保信号得到适当处理。重置信号处理程序可以防止由于信号处理中的错误而导致的无限循环或其他问题。

(5). 在Linux中,按下Control_C键将导致进程终止。然而,在伪终端上运行主shell时,按下Control_C键不会导致主shell终止。主shell是如何做到的?

回答: 主shell通过对信号进行处理,可能忽略或修改Control_C键生成的SIGINT信号,从而防止主shell终止。

(6). 在C编程中,回调函数(指针)作为参数传递给被调用的函数,该函数可能执行回调函数。回调函数和信号捕获器之间有什么区别?

回答: 回调函数是由程序员显式指定并传递给其他函数的函数,用于在特定事件发生时执行。信号捕获器是用于处理进程中断事件的特殊函数,由信号系统在发生特定事件时调用。

(7). 假设一个进程为SIGALRM(14)安装了信号捕获器。如果进程执行到不同的映像,会发生什么问题?如何处理这种问题?

回答: 如果进程执行到不同的映像,之前安装的信号捕获器可能不再有效。为了处理这种问题,进程需要在新映像中重新安装信号捕获器,以确保在新的执行环境中能够正确处理SIGALRM信号。

苏格拉底挑战

问答详情 Linux Signal Inquiry