0


【linux】信号(上)

1. 认识信号

信号是进程之间事件异步通知的一种方式,属于软中断

注意:

  1. 进程一定要有识别和处理信号的能力(即使信号没有产生,也要具备处理信号的能力,并且处理信号的能力,属于进程内置的一部分)
  2. 当一个进程收到了一个信号的时候,不一定会立刻处理这个信号
  3. 一个进程从信号产生,到信号被处理的这个阶段,会有时间窗口,即进程具有临时保存哪些信号已经发生的能力

2. **信号处理常见方式概览 **

处理信号分三种

  • 忽略此信号。
  • 执行该信号的默认处理动作(进程内置了,每一种信号有不同的处理方式)
  • 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉

(Catch)一个信号,(即自定义动作,自己规定哪一种信号对应哪一种处理方式)

3. ** 技术应用角度的信号**

  1. 用户输入命令,在Shell下启动一个前台进程

用户按下Ctrl+C ,这个键盘输入产生一个硬件中断,被OS获取,解释成信号,发送给目标前台进程

前台进程因为收到信号,进而引起进程退出

画图解释

注意:

  1. linux 中,一次登陆,一个终端,一般会配上一个 bash,每一个登录都只允许有一个前台进程(键盘上的输入,都是发送给前台进程的),可以允许有多个后台进程
  2. Ctrl+C 被解释成2号信号
  3. Ctrl-C 产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行,这样Shell不必等待进程结束就可以接受新的命令,启动新的进程

4. 系统定义的信号列表

  • kill -l

注意:

1 ~ 31 : 普通信号(一般以位图的形式储存在对应的进程PCB中,tast_struct 中有 signal ,其中比特位的 0 ,1 表示是否收到信号,比特位的位置(第几个)表示信号编号,所谓的发送信号就是更改对应进程信号位图的比特位)

这里是存在一些问题,如:信号可以发送很多次,但是迟迟没有处理信号,导致处理次数和发送信号次数不对等(处理次数可能会减少)

34 ~ 64 : 实时信号(接受信号后,立刻处理信号,一般以链表的形式存储,所以发送信号次数和处理次数是一样的)

  • man 7 signal

5. 修改特定的进程对于信号处理的动作

signal函数

功能:修改特定的进程对于信号处理的动作

typedef void (*sighandler_t)(int);

原型:

sighandler_t signal(int signum,sighandler_t handler);

参数:

signum:信号编号(可以通过查看信号列表得到)

handler:自定义处理方法

代码

注意:

signal函数只需要调用一次,往后都有效,且只有产生信号的时候,才会执行对应的方法

6. 信号的产生方式

  1. 键盘组合键

如:Ctrl + C --- 2号信号 Ctrl + \ ---- 3号信号

  1. kill 命令

kill -信号编号 + 进程pid

  1. 系统调用
  • kill函数

  • raise函数

  • abort函数

  1. 软件产生信号

如: 管道发送读端关闭,写段正常,此时会产生信号,杀死进程

7. 产生信号

(一)通过终端按键产生信号

注意:

Term 和 Core 都是会退出进程

**Core Dump **

  1. Core Dump概念: 当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部保存到磁盘上,文件名通常是core,这叫做Core Dump。(即 如果打开系统的 core dump 功能,一旦进程异常,OS 会将进程在内存中的运行信息,转储到进程的当前目录(磁盘)形成 core.pid 文件)
  2. 一个进程允许默认是不允许产生core文件的(因为core文件中可能包含用户密码等敏感信息,不安全)
  3. 开发调试阶段可以用ulimit命令改变这个限制,允许 产生core文件。 首先用ulimit命令改变Shell进程的Resource Limit,允许core文件最大为1024K: 如 ulimit -c 1024

写一个死循环,终端输入Ctrl + \ ,得到如下:

注意:

进程异常终止通常是因为有Bug,比如非法内存访问导致段错误, 事后可以用调试器检查core文件以查清错误原因,这叫做事后调

(二)调用系统函数向进程发信号

  • kill函数

int kill(pid_t pid,int sig);

pid : 进程pid ; sig : 信号编号

  • raise函数

int raise(int sig);

  • abort函数

void abort(void)

发送6号信号,且不管是否是否对6号自定义处理动作,都一定会退出进程

3. 由软件条件产生信号

这里主要介绍alarm 函数

原型:

unsigned int alarm(unsigned int seconds);

返回值:

因为 alarm 可以被多次调用,返回值是上一次alarm函数调用剩下的秒数(有可能上一个alarm函数时间没到,又被调用了)

注意:

调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动作是终止当前进程

**(三)硬件异常产生信号 **

硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号

(如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释 为SIGFPE信号发送给进程。又如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程)

标签: linux

本文转载自: https://blog.csdn.net/2301_79789645/article/details/142865302
版权归原作者 小小小汐- 所有, 如有侵权,请联系我们删除。

“【linux】信号(上)”的评论:

还没有评论