进程信号

信号:
信号就是软件中断,打断当中正在运行的进程,让该进程去处理信号事件
信号种类
一共62种信号
不可靠信号:1-31
可靠信号:34-62
信号的产生:
硬件产生:
ctrl+c:给前台发送一个SIGINT,中断当前的前台进程
ctrl+z:SIGSTP使进程暂停
ctrl+|:SIGQUIT,是进程崩溃,并产生coredump文件
软件产生:
kill [pid] SIGTERM
kill -[signalno] [pid]
函数产生:
kill函数 kill(pid_t pid, int signo)
abort函数 谁调用谁退出 SIGBRA
alarm 定时器函数
信号注册分两种情况:
非可靠信号1-31:
更改sig位图对应的比特位为1,在sigqueue队列当中添加对应信号对应的节点
当多次收到同一个信号时,只添加一次节点,受到同样的信号被抛弃
可靠信号34-62:
更改sig位图对应的比特位为1,在sigqueue队列当中添加对应信号对应的节点
当多次收到同一个信号时,判断sig位图是否为1,并在sigqueue队列当中添加节点

信号的注销分两种情况:
非可靠信号1-31:
更改sig位图对应的比特位为0,在sigqueue队列当中删除对应信号对应的节点
可靠信号34-62:
将带注销的信号在sigqueue队列当中盘算,当前信号节点在队列中是否还有同样的类型
有:不改变位图,删除一个节点
没有:将位图改比特位置为0

在这里插入图片描述
信号的捕捉处理:
默认处理:执行一个动作、函数
忽略处理:不做什么,僵尸进程原因SIGCHILD信号
自定义处理:sighandler_t signal (int signum, sighandler_t handler)

操作系统对信号的默认处理:
当sig位图收到一个信号时,意味着sig位图被置为1了,操作系统处理信号的时候就会从PCB当中找到sighang_struct结构体指针,从而找到sa_handler,进而操作系统回去调用sa_handler保存的函数地址
signal相当于改变了sa_handler保存的函数地址,当收到自定义信号时,操作系统内核会去调用sa_handler保存的函数地址,也就达到了更改函数处理的目的

我们注册的函数,被称为回调函数,不是我们来调用,而是当我们收到自定义信号操作系统会来执行。
在这里插入图片描述
sigaction相当于改变了action数组元素,改变了整个结构体来达到修改处理函数地址的目的
signal调用sigaction函数实现

信号捕捉流程
在这里插入图片描述
进入内核态条件:
1.使用系统调用
2.使用库函数,库函数底层调用系统调用
3.程序异常
3.1空指针访问
3.2内存问越界

### 信号的概念 信号进程间通信的一种方式,用于通知进程发生了某种特定事件。在 Linux 系统中,有多种常见的信号,每种信号都有其特定的编号和名称,例如 SIGINT(编号 2,通常由 Ctrl+C 触发)、SIGTERM(编号 15,用于正常终止进程)等。信号的管理涉及信号的产生、存储、处理等多个方面,信号的存储结构与进程的状态相关,主要涉及 block 表、pending 表和 handler 表 [^1][^2][^3]。 ### 信号的产生 - **通过键盘产生信号**:用户在终端输入特定的组合键可以产生信号,如 Ctrl+C 会产生 SIGINT 信号,用于终止当前前台进程;Ctrl+\ 会产生 SIGQUIT 信号 [^3]。 - **调用系统函数向进程发送信号**: - **kill**:可以给任意进程发送任意信号,函数原型为 `int kill(pid_t pid, int sig);`,其中 `pid` 是目标进程的 ID,`sig` 是要发送的信号编号 [^1][^3]。 - **raise**:用于给进程本身发送任意信号,函数原型为 `int raise(int sig);`,相当于 `kill(getpid(), sig)` [^1][^3]。 - **abort**:使当前进程异常终止,它会发送 SIGABRT 信号给当前进程,函数原型为 `void abort(void);` [^3]。 - **硬件异常产生信号**:当硬件出现错误时,会产生相应的信号。例如,除零错误会产生 SIGFPE 信号,访问非法内存会产生 SIGSEGV 信号 [^2][^3]。 - **软件条件产生信号**:某些软件条件满足时会产生信号,如 `alarm` 函数可以设置一个定时器,当定时器超时后会产生 SIGALRM 信号 [^1][^3]。 ### 信号的处理方式 - **默认处理**:每个信号都有其默认的处理动作,如终止进程、忽略信号、暂停进程等。 - **忽略处理**:进程可以选择忽略某些信号,即不做任何处理。 - **自定义处理**:进程可以通过信号处理函数来对特定信号进行自定义处理。在 Linux 中,可以使用 `signal` 或 `sigaction` 函数来设置信号的处理动作 [^1][^3]。 ### 信号的捕捉 - **自定义捕捉**:可以使用 `signal` 或 `sigaction` 函数来注册自定义的信号处理函数。例如,使用 `signal` 函数的示例代码如下: ```c #include <stdio.h> #include <signal.h> void handler(int signum) { printf("Received signal %d\n", signum); } int main() { signal(SIGINT, handler); while (1) { // 主循环 } return 0; } ``` - **无法被捕捉的信号**:有些信号是无法被捕捉的,如 SIGKILL(编号 9)和 SIGSTOP(编号 19),它们用于强制终止或暂停进程 [^3]。 - **内核如何实现信号的捕捉**:当信号产生时,内核会在适当的时候检查进程信号处理表,根据信号的处理方式进行相应的处理。如果是自定义处理,会调用注册的信号处理函数 [^3]。 ### 信号的阻塞 - **信号的状态**:信号有三种状态,分别是产生、未决和递达。信号产生后,如果被阻塞,则处于未决状态;当阻塞解除后,信号才会递达并进行处理 [^3][^5]。 - **信号在内核中的表示**:信号在内核中通过 block 表、pending 表和 handler 表来表示。block 表用于记录哪些信号被阻塞,pending 表用于记录哪些信号已经产生但尚未递达,handler 表用于记录信号的处理动作 [^2][^3][^5]。 - **sigset_t 信号集**:`sigset_t` 是一种数据类型,用于表示信号集。可以使用信号集操作函数来对信号集进行操作,如 `sigemptyset`、`sigfillset`、`sigaddset`、`sigdelset` 等 [^2][^3]。 - **sigprocmask 设置阻塞信号集**:`sigprocmask` 函数用于设置进程的阻塞信号集,函数原型为 `int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);` [^1][^3]。 - **sigpending 获取未决信号集**:`sigpending` 函数用于获取当前进程的未决信号集,函数原型为 `int sigpending(sigset_t *set);` [^3]。 ### 信号的补充 - **volatile 关键字**:`volatile` 关键字用于保持内存的可见性,在信号处理函数中使用 `volatile` 可以确保变量的值不会被编译器优化而导致的问题 [^2][^3]。 - **SIGCHLD 信号**:当子进程终止或停止时,会向父进程发送 SIGCHLD 信号父进程可以通过捕捉该信号来进行资源回收等操作 [^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值