1 信号入门
1.1 生活中的信号
- 音信号:如电话铃声、门铃、汽车喇叭声等。
- 视觉信号:如交通信号灯、手语、交通标志、指示牌等。
- 触觉信号:如触摸、压力变化、温度变化等。
- 嗅觉信号:如花香、食物的香味、某些化学物质的气味等。
- 味觉信号:如食物的味道,可以是甜、酸、苦、咸、鲜等。
- 生物信号:如心跳、脑电波、激素水平变化等。
- 社会信号:如身体语言、面部表情、社交礼仪等。
- 电磁信号:如无线通信信号、电视和广播信号、雷达信号等。
- 数字信号:如计算机数据、网络传输的信息、数字音频和视频信号等。
- 环境信号:如天气变化、季节更替、自然现象(如日出日落)等。
感性认识一下
a.你么认识这些信号的? 有人教我->我记住了
何为认识:1. 识别信号 2. 知道信号的处理方式b.即便是我们现在没有信号产生,我也知道信号产生之后,我该干什么。
c.信号产生了,我们可能并不立即处理这个信号,而是选择在合适的时候。因为我们可能正在做更重要的事情,所以信号产生时一直到信号处理时会有一个时间窗口。在这个时间窗口内,你必须记住信号到来!
对于进程来说
- 进程必须具有 识别+能够处理信号 和信号没有产生,也要具备处理信号的能力。信号的处理能力,属于进程内置功能的一部分
- 进程即便是没有收到信号,也能知道哪些信号该怎么处理
- 当进程真的收到了一个具体的信号的时候,进程可能并不会立即处理这个信号,而是选择一个合适的时候
- 当信号产生,到信号开始被处理,一定会有时间窗口,进程需要具有临时保存哪些信号已经发生了的能力
信号处理的方式,下面三选一
- 默认动作
- 忽略
- 自定义动作
1.2 前台进程和后台进程
- 前台进程:
- 前台进程是与终端交互的进程。它们可以直接从键盘接收输入,并在终端上显示输出。
- 当你启动一个程序时,如果没有特别指定,它默认在前台运行。
- 前台进程在用户与终端交互时会阻塞用户操作,直到该进程结束或被暂停。
- 可以通过按
Ctrl + Z
将前台进程挂起,然后使用fg
命令将其恢复到前台。
- 后台进程:
- 后台进程是指那些不需要与终端交互,可以独立运行的进程。
- 将进程放到后台运行,可以通过在命令的末尾添加
&
符号来实现,如:command &
。 - 后台进程不会阻塞用户对终端的使用,用户可以继续执行其他命令。
- 后台进程的输出默认也会发送到终端,但可以通过重定向操作符(如
>
或>>
)将其输出到文件中。 - 可以使用
jobs
命令查看后台进程的状态,使用bg
命令将挂起的后台进程恢复运行。
1.3 ctrl+c为什么能杀掉前台进程
- 首先,Linux在一次登陆中,一个终端,一般会配上一个bash。每一个终端,只允许一个进程是前台进程,可以允许多个进程是后台进程。前台进程可以获取并解析键盘输入,后台进程不可以
- ctrl + c是被前台进程收到的
- ctrl + c的本质是进程将其解释为收到了2号新号
1.4 验证当我们ctrl+c后,进程收到的是2号信号
使用一个函数,该函数可以捕捉信号,之后自定义该信号的默认处理方式
NAME
signal - ANSI C signal handling
LIBRARY
Standard C library (libc, -lc)
SYNOPSIS
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
DESCRIPTION
signal() sets the disposition of the signal signum to handler,
which is either SIG_IGN, SIG_DFL, or the address of a programmer-
defined function (a "signal handler").
signal() 函数用于设置信号 signum 的处理方式,处理方式可以是 SIG_IGN、SIG_DFL,
或者是一个程序员定义的函数(称为“signal handler”)。
void MyHandler(int sigNo)
{
if(sigNo == 2) {
cout << "Signal 2 two has been captured" << endl;
exit(2);
}
}
int main()
{
// 捕捉该信号,使用SIGINT或者2都可以。只需要设置一次,从这句往后,一直都有效
// signal(2, MyHandler);
signal(SIGINT, MyHandler);
while(true) {
cout << "I am a process" << endl;
sleep(1);
}
return 0;
}
按下ctrl+c会打印出上面的语句,即可证明
1.5 键盘数据是如何输入给内核的
首先,键盘被摁下,肯定是OS先知道。OS怎么知道键盘上有数据了?
如上图,OS加载到内存,键盘输入后,实际上输入到OS内存所在的一个缓冲区上,下文详细介绍了此过程
- 当用户按下或释放键盘上的一个键时,键盘硬件会生成一个中断信号。这个信号通知CPU,表示有新的输入数据可用(这样,OS就知道键盘上有数据了)。
- 操作系统有一个或多个中断处理程序(interrupt handler),它们是专门编写的代码,用于响应特定的中断信号。对于键盘输入,有一个特定的中断处理程序会被调用。
- 中断处理程序会被加载到CPU的上下文中,并执行。它会从键盘的硬件缓冲区中读取按键数据。这个缓冲区是键盘硬件上的一个小存储区域,用于临时存储按键信息,直到操作系统读取它。
- 读取到的按键数据会被传递给操作系统的更高级别的驱动程序。驱动程序会进一步处理这些数据,比如转换成字符或命令。
- 操作系统会将按键事件通知给相应的应用程序。
- 应用程序接收到按键事件后,会根据其逻辑进行响应,比如执行命令、输入文本或更改程序状态。
上图表示OS从键盘读取数据的流程
用户按下Ctrl+C
, 这个键盘输入产生一个硬件中断,被OS获取,解释成信号(2号信号),发送给目标前台进程 前台进程因为收到信号,进而引起进程退出
1.6 异步
“异步”(Asynchronous),用于描述两个或多个事件或过程在没有严格同步的情况下发生的操作模式。在异步操作中,任务的发起者(例如,一个程序或进程)不需要等待任务完成就可以继续执行其他工作。
1.7 总结
Ctrl-C
产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行, 这样Shell不必等待进程结束就可以接受新的命令, 启动新的进程。- Shell可以同时运行一个前台进程和任意多个后台进程, 只有前台进程才能接到像
Ctrl-C
这种控制键产生的信号。 - 前台进程在运行过程中用户随时可能按下
Ctrl-C
而产生一个信号, 也就是说该进程的用户空间代码执行到任何地方都有可能收到SIGINT
信号而终止, 所以信号的产生相对于我们自己的代码运行来说是异步(Asynchronous)的。