学习笔记9
关于知识点
知识点归纳
第六章 信号和信号处理
- 6.1 信号和中断
- 信号:
信号是计算机系统中的一个概念,它表示一种特殊的变量或值,用于表示系统中的某些状态或事件。信号可以在程序运行过程中由操作系统或其他程序发送,以指示特定的操作或事件发生。常见的信号有:
-
软中断(软信号):由软件产生的信号,如进程自行设置的信号,用于进程间的通信。
-
硬件信号:由硬件产生的信号,如时钟信号、I/O设备产生的信号等。
- 中断:
中断是计算机系统在执行过程中,遇到非正常或非预期的急需处理事件时,暂停当前程序执行,转去处理中断事件,处理完毕后返回原程序继续执行的过程。中断机制是计算机系统中的重要组成部分,用于处理系统中的异常事件和实时事件。
中断机制的基本流程如下:
-
中断请求:当发生中断事件时,中断源向处理器发出中断请求信号。
-
中断响应:处理器收到中断请求信号后,暂停当前程序执行,转去执行中断处理程序。
-
处理中断:处理器执行中断处理程序,处理中断事件。
-
恢复执行:处理完毕后,处理器返回原程序继续执行。
- 信号与中断的关系:
信号和中断之间有着密切的联系。在计算机系统中,信号可以触发中断,用于表示中断事件的发生。进程可以通过捕获和处理信号,来实现对中断事件的响应。信号处理程序通常在中断处理程序中实现,用于处理特定类型的中断事件。
信号是表示特定状态或事件的变量,而中断是计算机系统在处理过程中遇到非正常事件时采取的一种机制。信号与中断密切相关,信号可以触发中断,处理器通过执行中断处理程序来响应和处理中断事件。在实际应用中,信号与中断机制共同保证了计算机系统的正常运行和实时响应能力。
- 6.2 Unix/Linux信号示例
- 6.3 Unix/Linux中的信号处理
- 6.3.1 信号类型
Unix/Linux系统中定义了多种不同的信号类型,每种信号都对应一个特定的事件或者动作。 - 6.3.2 信号的来源
- 6.3.3 进程PROC结构体中的信号
- 6.3.4 信号处理函数
进程可以为每种信号注册一个信号处理函数,用于在接收到该信号时进行特定的处理动作。 - 6.3.5 安装信号捕捉函数
在Unix/Linux中,可以通过sigaction()函数来安装信号捕捉函数,用于在接收到特定的信号时执行用户自定义的处理动作。
- 6.3.1 信号类型
- sigaction()函数简介:sigaction()是Unix/Linux系统中用于安装信号处理函数的函数,其原型为:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
其中signum表示所要处理的信号的编号,act是一个指向结构体sigaction的指针,包含了新的信号处理函数及相关标志,oldact是一个结构体sigaction的指针,用于保存之前的信号处理函数及相关标志。 - 自定义信号处理函数:用户可以自定义信号处理函数,该函数的原型为void signal_handler(int signum),signum表示接收到的信号编号。在这个函数中可以编写对接收到信号的特定处理。
- 安装信号捕捉函数:使用sigaction()函数可以安装自定义的信号捕捉函数,使得在接收到特定信号时可以执行自定义的处理。首先需要定义一个struct sigaction类型的变量,设置其sa_handler成员为指向自定义的信号处理函数,然后调用sigaction()函数安装。
- 存储之前的处理函数:使用sigaction()函数时,可以传递一个非空的指向结构体sigaction的指针作为第三个参数,用于保存之前的信号处理函数及相关标志。
- 信号处理函数的安全性:在信号处理函数中应该尽量只调用异步信号安全的函数,因为在处理信号时会中断原有的程序流程,如果调用非安全的函数可能会导致不可预料的结果。
- 6.4 信号处理步骤
-
产生信号:信号的产生可以由操作系统、其他进程或者内核发起。比如当用户按下CTRL+C键时,会向前台进程组的所有进程发送SIGINT信号。
-
传递信号:一旦信号产生,操作系统会负责将该信号传递给目标进程。如果目标进程允许接收该信号,操作系统会将信号传递给目标进程。
-
信号接收:目标进程接收到信号后,会根据信号处理的规则进行处理。如果该信号不被阻塞且有相应的信号处理函数,那么信号处理函数将会被调用。
-
信号处理:接收到信号的进程将根据之前注册的信号处理函数执行相应的操作,可能包括特定的处理逻辑、清理工作或者记录日志。
-
恢复原状态:一旦信号处理函数执行完毕,控制权将返回到原来的上下文,进程继续执行原来的流程。
- 6.5 信号与异常
-
信号:信号是一种异步的事件机制,用于通知进程发生了某种事件,比如错误、中断或者一个特殊的命令。在Unix/Linux系统中,可以通过系统调用kill()向进程发送信号,比如SIGKILL、SIGSTOP、SIGINT等。进程可以注册信号处理函数,用于接收信号并执行相应的处理。
-
异常:异常是指在程序执行过程中发生的、与正常处理流程不符的情况。例如,除零、内存访问错误、非法指令等。操作系统可以通过异常处理机制来捕获并处理这些异常情况,通常会导致进程的异常终止或者内核处理。
-
区别:信号是一种更轻量级的进程间通信机制,用于通知进程发生了某种事件;而异常是指程序执行中的异常情况,通常需要操作系统的介入进行处理。
-
相关性:在处理异常的过程中,操作系统有时也会使用信号机制来通知进程发生了异常,比如SIGSEGV信号代表发生了段错误。此外,在一些情况下,程序可能也会通过信号机制来处理异常情况,比如捕获SIGFPE信号以处理除零异常。
- 6.6 信号用作IPC
- 6.7 Linux中的IPC
- 6.7.1 管道和FIFO
管道(Pipe):
- 管道是一种半双工的通信机制,用于在父子进程或者通过相关进程之间进行通信。
- 管道有两种类型:匿名管道和命名管道。匿名管道只能用于具有共同祖先的进程间通信;而命名管道可以用于进程之间无论是否有共同祖先。
FIFO(命名管道):
- FIFO是一种特殊类型的文件,在文件系统中以特殊类型的文件节点存在。
- FIFO是命名管道的一种,可以用于任意进程之间进行通信,无论是否有共同祖先。
- 使用mkfifo()系统调用可以创建FIFO,它通过文件系统提供命名管道的功能。
共同特点:
-
管道和FIFO都属于进程间通信的机制,用于在不同进程之间进行数据交换。
-
在使用管道和FIFO时,通信双方必须遵循一定的输入输出规则。其中,管道数据传输是单向的,而FIFO则是双向的。
-
管道和FIFO都是通过文件描述符进行操作和访问的,因此它们都具有一些文件的属性并且可以使用类似的系统调用来进行读写操作。
- 6.7.2 信号
-
信号的类型:Linux系统定义了多种不同的信号类型,每种信号都对应一个特定的事件或者动作,比如终止进程、中断进程、暂停进程等。一些常见的信号包括SIGKILL(终止进程)、SIGSTOP(暂停进程)、SIGINT(中断进程)等。
-
信号的发送和接收:可以使用系统调用kill()向另一个进程或者自身发送信号。当进程接收到信号时,会根据预先注册的信号处理函数对信号进行处理。
-
信号处理函数:进程可以为每种信号注册一个信号处理函数,用于在接收到该信号时进行特定的处理动作。可以使用信号处理函数来对接收到的信号进行处理、记录日志或者清理资源。
-
信号的阻塞和解除阻塞:进程可以通过系统调用sigprocmask()来阻塞或者解除阻塞某些信号的处理,从而控制信号的处理时机。
-
信号的默认处理动作:每种信号都有默认的处理动作,比如终止进程、忽略信号或者终止进程并产生核心转储文件等。
-
信号的处理机制:Linux系统通过信号处理表和信号处理队列来管理和处理进程接收到的信号。
-
信号的编号和名称:每种信号都有一个唯一的编号和一个对应的名称,可以通过信号的编号或名称来向进程发送信号。
- 6.7.3 System V IPC
- 6.7.4 POSIX消息队列
- 6.7.5 线程同步机制
-
信号量:信号量是一种常用的进程同步机制,它通过一个整数值来表示资源的可用性。进程可以通过执行semsignal()和semwait()原语来发送和接收信号,实现进程间的同步。
-
记录锁(文件锁):记录锁是一种用于保护共享资源的同步机制。当一个进程需要访问共享资源时,它需要先获取锁,如果锁已经被其他进程占用,那么当前进程会被阻塞,直到锁被释放。
-
互斥锁(mutex):互斥锁是一种更为高效的同步机制,它同样用于保护共享资源。互斥锁通过一个整数值来表示锁的状态,只有当锁的状态为0时,进程才能获取锁。
-
共享内存:共享内存是一种高效的进程同步机制,多个进程可以共享同一块内存区域,从而实现进程间的数据交换。Linux中的mutex锁和信号量也可以用于共享内存的保护。
-
管道和FIFO:管道和FIFO是一种进程间通信的方式,它们可以用于实现进程间的同步。管道是一种半双工的通信方式,数据只能从父进程传递到子进程;而FIFO则是全双工的通信方式,允许进程间双向通信。
-
消息队列:消息队列是一种另一种进程间通信的方式,它允许进程发送和接收消息,从而实现进程间的同步。
-
套接字:套接字是一种通用的进程间通信方式,它可以用于实现不同进程之间的同步。套接字支持多种协议,如TCP/IP、UDP等。
- 6.7.6 套接字