1. 知识回顾
前文已介绍 Ctrl+C 可以杀死前台进程,本文详解 Ctrl+C 是如何变成信号的。
2. Ctrl+C 如何转化为信号
硬件中断
操作系统为了保证安全,进程无法直接读取键盘数据。基于 Linux'一切皆文件'的思想,键盘也是文件,操作系统会先读取键盘缓冲区文件。
操作系统如何知道键盘上有数据要读取?CPU 上的针脚和外设间接相连,键盘有数据时会向 CPU 发送硬件中断,由 CPU 告诉操作系统将键盘数据拷贝到键盘文件缓冲区。
计算机外设众多,每个外设均可向 CPU 发送中断。如何确保是键盘发送的中断?每个中断都有唯一编号,称为中断号。CPU 根据中断号区分不同中断。
外设向 CPU 发送中断,CPU 解释出中断号。保护模式下,CPU 根据中断号到中断描述符表找出对应中断例程的地址,然后跳转执行,结束后通过 iret 返回。
该中断例程可以是操作系统将键盘外设上的数据拷贝到键盘文件缓冲区。若多个硬件同时发送中断,操作系统会串行处理。
参考《Linux 内核设计与实现》:内核负责管理硬件设备,提供中断机制。当硬件设备和系统通信时,发出异步中断信号打断处理器执行。内核通过中断号查找相应的中断服务程序并调用响应和处理。例如敲击键盘时,键盘控制器发送中断信号告知系统缓冲区有数据到来。内核调用相应服务程序处理数据,通知控制器继续输入。为保证同步,内核可停用中止。
信号
上方讲的是硬件中断,信号是用软件的方式模拟硬件中断。
变成信号的整个过程
用户按下 Ctrl+C,键盘输入产生硬件中断,被操作系统获取,解释成信号,发送给目标前台进程。前台进程收到信号,引起进程退出。
回显的含义
正常情况下,从键盘输入的数据会显示到显示器上,这是因为操作系统将键盘缓冲区的数据拷贝到显示器的缓冲区。
注:图中的'键盘文件'和'显示器文件'是根据 Linux'一切皆文件'的思想,将硬件的内容抽象为文件。
不回显的含义:键盘缓冲区的数据不拷贝到显示器的缓冲区。
3. 信号产生是异步的
前台进程在运行过程中用户随时可能按下 Ctrl+C 而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到 SIGINT 信号而终止,所以信号相对于进程的控制流程来说是异步 (Asynchronous) 的。
- 例子理解:操作系统不知道用户什么时候会按键盘,这是异步的。
- 对立面理解:同步的反义词是异步。
信号是进程之间事件异步通知的一种方式,属于软中断,软中断是仿照硬件中断实现的软件逻辑。
4. 信号的产生:使用系统调用
新建以下文件结构:
test_signal
├── hello_world.cpp
├── makefile
└── test_signal.cpp
hello_world.cpp 写入打印 Hello World 的代码。 makefile 编写编译规则。
kill
作用:向指定进程发送指定的信号。 kill 的参数:
- pid: 进程号
- sig: 信号编号
编写"kill -signo pid"命令
test_signal.cpp 写入:
#include <unistd.h>
#include <iostream>
#include <signal.h>
int main(int argc, * argv[]) {
(argc != ) {
std::cout << << std::endl;
();
}
std::string signo_s = argv[];
std::string pid_s = argv[];
signo = std::(std::(signo_s, ));
pid = (pid_s);
(signo < || pid > ) {
std::cout << << std::endl;
();
}
((pid, signo)) {
();
();
}
std::cout << << std::endl;
;
}


